2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.FeatureColourI;
24 import jalview.api.FeatureSettingsControllerI;
25 import jalview.bin.Cache;
26 import jalview.datamodel.SequenceFeature;
27 import jalview.datamodel.SequenceI;
28 import jalview.gui.Help.HelpId;
29 import jalview.io.JalviewFileChooser;
30 import jalview.io.JalviewFileView;
31 import jalview.schemabinding.version2.JalviewUserColours;
32 import jalview.schemes.FeatureColour;
33 import jalview.util.Format;
34 import jalview.util.MessageManager;
35 import jalview.util.Platform;
36 import jalview.util.QuickSort;
37 import jalview.viewmodel.AlignmentViewport;
38 import jalview.ws.dbsources.das.api.jalviewSourceI;
40 import java.awt.BorderLayout;
41 import java.awt.Color;
42 import java.awt.Component;
44 import java.awt.Graphics;
45 import java.awt.GridLayout;
46 import java.awt.Rectangle;
47 import java.awt.event.ActionEvent;
48 import java.awt.event.ActionListener;
49 import java.awt.event.ItemEvent;
50 import java.awt.event.ItemListener;
51 import java.awt.event.MouseAdapter;
52 import java.awt.event.MouseEvent;
53 import java.awt.event.MouseMotionAdapter;
54 import java.beans.PropertyChangeEvent;
55 import java.beans.PropertyChangeListener;
57 import java.io.FileInputStream;
58 import java.io.FileOutputStream;
59 import java.io.InputStreamReader;
60 import java.io.OutputStreamWriter;
61 import java.io.PrintWriter;
62 import java.util.Arrays;
63 import java.util.Hashtable;
64 import java.util.Iterator;
65 import java.util.List;
68 import java.util.Vector;
70 import javax.help.HelpSetException;
71 import javax.swing.AbstractCellEditor;
72 import javax.swing.BorderFactory;
73 import javax.swing.Icon;
74 import javax.swing.JButton;
75 import javax.swing.JCheckBox;
76 import javax.swing.JCheckBoxMenuItem;
77 import javax.swing.JColorChooser;
78 import javax.swing.JDialog;
79 import javax.swing.JInternalFrame;
80 import javax.swing.JLabel;
81 import javax.swing.JLayeredPane;
82 import javax.swing.JMenuItem;
83 import javax.swing.JPanel;
84 import javax.swing.JPopupMenu;
85 import javax.swing.JScrollPane;
86 import javax.swing.JSlider;
87 import javax.swing.JTabbedPane;
88 import javax.swing.JTable;
89 import javax.swing.ListSelectionModel;
90 import javax.swing.SwingConstants;
91 import javax.swing.SwingUtilities;
92 import javax.swing.event.ChangeEvent;
93 import javax.swing.event.ChangeListener;
94 import javax.swing.table.AbstractTableModel;
95 import javax.swing.table.TableCellEditor;
96 import javax.swing.table.TableCellRenderer;
98 public class FeatureSettings extends JPanel implements
99 FeatureSettingsControllerI
101 DasSourceBrowser dassourceBrowser;
103 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
105 JPanel settingsPane = new JPanel();
107 JPanel dasSettingsPane = new JPanel();
109 final FeatureRenderer fr;
111 public final AlignFrame af;
113 Object[][] originalData;
115 private float originalTransparency;
117 final JInternalFrame frame;
119 JScrollPane scrollPane = new JScrollPane();
125 JSlider transparency = new JSlider();
127 JPanel transPanel = new JPanel(new GridLayout(1, 2));
129 public FeatureSettings(AlignFrame af)
132 fr = af.getFeatureRenderer();
133 // allow transparency to be recovered
134 transparency.setMaximum(100 - (int) ((originalTransparency = fr
135 .getTransparency()) * 100));
140 } catch (Exception ex)
142 ex.printStackTrace();
148 public String getToolTipText(MouseEvent e)
150 if (table.columnAtPoint(e.getPoint()) == 0)
153 * Tooltip for feature name only
155 return JvSwingUtils.wrapTooltip(true, MessageManager
156 .getString("label.feature_settings_click_drag"));
161 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
162 table.setFont(new Font("Verdana", Font.PLAIN, 12));
163 table.setDefaultRenderer(Color.class, new ColorRenderer());
165 table.setDefaultEditor(Color.class, new ColorEditor(this));
167 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
168 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
169 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
171 table.addMouseListener(new MouseAdapter()
174 public void mousePressed(MouseEvent evt)
176 selectedRow = table.rowAtPoint(evt.getPoint());
177 if (evt.isPopupTrigger())
179 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
180 table.getValueAt(selectedRow, 1), fr.getMinMax(),
181 evt.getX(), evt.getY());
183 else if (evt.getClickCount() == 2)
185 boolean invertSelection = evt.isAltDown();
186 boolean toggleSelection = Platform.isControlDown(evt);
187 boolean extendSelection = evt.isShiftDown();
188 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
189 invertSelection, extendSelection, toggleSelection,
190 (String) table.getValueAt(selectedRow, 0));
194 // isPopupTrigger fires on mouseReleased on Windows
196 public void mouseReleased(MouseEvent evt)
198 selectedRow = table.rowAtPoint(evt.getPoint());
199 if (evt.isPopupTrigger())
201 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
202 table.getValueAt(selectedRow, 1), fr.getMinMax(),
203 evt.getX(), evt.getY());
208 table.addMouseMotionListener(new MouseMotionAdapter()
211 public void mouseDragged(MouseEvent evt)
213 int newRow = table.rowAtPoint(evt.getPoint());
214 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
217 * reposition 'selectedRow' to 'newRow' (the dragged to location)
218 * this could be more than one row away for a very fast drag action
219 * so just swap it with adjacent rows until we get it there
221 Object[][] data = ((FeatureTableModel) table.getModel())
223 int direction = newRow < selectedRow ? -1 : 1;
224 for (int i = selectedRow; i != newRow; i += direction)
226 Object[] temp = data[i];
227 data[i] = data[i + direction];
228 data[i + direction] = temp;
230 updateFeatureRenderer(data);
232 selectedRow = newRow;
236 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
237 // MessageManager.getString("label.feature_settings_click_drag")));
238 scrollPane.setViewportView(table);
240 dassourceBrowser = new DasSourceBrowser(this);
241 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
243 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
245 fr.findAllFeatures(true); // display everything!
248 discoverAllFeatureData();
249 final PropertyChangeListener change;
250 final FeatureSettings fs = this;
251 fr.addPropertyChangeListener(change = new PropertyChangeListener()
254 public void propertyChange(PropertyChangeEvent evt)
256 if (!fs.resettingTable && !fs.handlingUpdate)
258 fs.handlingUpdate = true;
259 fs.resetTable(null); // new groups may be added with new seuqence
260 // feature types only
261 fs.handlingUpdate = false;
267 frame = new JInternalFrame();
268 frame.setContentPane(this);
269 if (Platform.isAMac())
271 Desktop.addInternalFrame(frame,
272 MessageManager.getString("label.sequence_feature_settings"),
277 Desktop.addInternalFrame(frame,
278 MessageManager.getString("label.sequence_feature_settings"),
282 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
285 public void internalFrameClosed(
286 javax.swing.event.InternalFrameEvent evt)
288 fr.removePropertyChangeListener(change);
289 dassourceBrowser.fs = null;
292 frame.setLayer(JLayeredPane.PALETTE_LAYER);
295 protected void popupSort(final int selectedRow, final String type,
296 final Object typeCol, final Map<String, float[][]> minmax, int x,
299 final FeatureColourI featureColour = (FeatureColourI) typeCol;
301 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
302 "label.settings_for_param", new String[] { type }));
303 JMenuItem scr = new JMenuItem(
304 MessageManager.getString("label.sort_by_score"));
306 final FeatureSettings me = this;
307 scr.addActionListener(new ActionListener()
311 public void actionPerformed(ActionEvent e)
313 me.af.avc.sortAlignmentByFeatureScore(Arrays
314 .asList(new String[] { type }));
318 JMenuItem dens = new JMenuItem(
319 MessageManager.getString("label.sort_by_density"));
320 dens.addActionListener(new ActionListener()
324 public void actionPerformed(ActionEvent e)
326 me.af.avc.sortAlignmentByFeatureDensity(Arrays
327 .asList(new String[] { type }));
334 final float[][] typeMinMax = minmax.get(type);
336 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
337 * this is broken at the moment and isn't that useful anyway!
338 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
341 * public void actionPerformed(ActionEvent e) {
342 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
343 * null); } else { minmax.put(type, typeMinMax); } }
349 if (typeMinMax != null && typeMinMax[0] != null)
351 // if (table.getValueAt(row, column));
352 // graduated colourschemes for those where minmax exists for the
353 // positional features
354 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
356 mxcol.setSelected(!featureColour.isSimpleColour());
358 mxcol.addActionListener(new ActionListener()
360 JColorChooser colorChooser;
363 public void actionPerformed(ActionEvent e)
365 if (e.getSource() == mxcol)
367 if (featureColour.isSimpleColour())
369 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
371 fc.addActionListener(this);
375 // bring up simple color chooser
376 colorChooser = new JColorChooser();
377 JDialog dialog = JColorChooser.createDialog(me,
378 "Select new Colour", true, // modal
379 colorChooser, this, // OK button handler
380 null); // no CANCEL button handler
381 colorChooser.setColor(featureColour.getMaxColour());
382 dialog.setVisible(true);
387 if (e.getSource() instanceof FeatureColourChooser)
389 FeatureColourChooser fc = (FeatureColourChooser) e
391 table.setValueAt(fc.getLastColour(), selectedRow, 1);
396 // probably the color chooser!
398 new FeatureColour(colorChooser.getColor()),
401 me.updateFeatureRenderer(
402 ((FeatureTableModel) table.getModel()).getData(),
411 JMenuItem selCols = new JMenuItem(
412 MessageManager.getString("label.select_columns_containing"));
413 selCols.addActionListener(new ActionListener()
416 public void actionPerformed(ActionEvent arg0)
418 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
422 JMenuItem clearCols = new JMenuItem(
423 MessageManager.getString("label.select_columns_not_containing"));
424 clearCols.addActionListener(new ActionListener()
427 public void actionPerformed(ActionEvent arg0)
429 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
433 JMenuItem hideCols = new JMenuItem(
434 MessageManager.getString("label.hide_columns_containing"));
435 hideCols.addActionListener(new ActionListener()
438 public void actionPerformed(ActionEvent arg0)
440 fr.ap.alignFrame.hideFeatureColumns(type, true);
443 JMenuItem hideOtherCols = new JMenuItem(
444 MessageManager.getString("label.hide_columns_not_containing"));
445 hideOtherCols.addActionListener(new ActionListener()
448 public void actionPerformed(ActionEvent arg0)
450 fr.ap.alignFrame.hideFeatureColumns(type, false);
456 men.add(hideOtherCols);
457 men.show(table, x, y);
461 * true when Feature Settings are updating from feature renderer
463 private boolean handlingUpdate = false;
466 * contains a float[3] for each feature type string. created by setTableData
468 Map<String, float[]> typeWidth = null;
471 synchronized public void discoverAllFeatureData()
473 Vector<String> allFeatures = new Vector<String>();
474 Vector<String> allGroups = new Vector<String>();
475 SequenceFeature[] tmpfeatures;
477 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
479 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
480 .getSequenceFeatures();
481 if (tmpfeatures == null)
487 while (index < tmpfeatures.length)
489 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
495 if (tmpfeatures[index].getFeatureGroup() != null)
497 group = tmpfeatures[index].featureGroup;
498 if (!allGroups.contains(group))
500 allGroups.addElement(group);
501 checkGroupState(group);
505 if (!allFeatures.contains(tmpfeatures[index].getType()))
507 allFeatures.addElement(tmpfeatures[index].getType());
519 * Synchronise gui group list and check visibility of group
522 * @return true if group is visible
524 private boolean checkGroupState(String group)
526 boolean visible = fr.checkGroupVisibility(group, true);
528 if (groupPanel == null)
530 groupPanel = new JPanel();
533 boolean alreadyAdded = false;
534 for (int g = 0; g < groupPanel.getComponentCount(); g++)
536 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
539 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
549 final String grp = group;
550 final JCheckBox check = new JCheckBox(group, visible);
551 check.setFont(new Font("Serif", Font.BOLD, 12));
552 check.addItemListener(new ItemListener()
555 public void itemStateChanged(ItemEvent evt)
557 fr.setGroupVisibility(check.getText(), check.isSelected());
558 af.alignPanel.getSeqPanel().seqCanvas.repaint();
559 if (af.alignPanel.overviewPanel != null)
561 af.alignPanel.overviewPanel.updateOverviewImage();
564 resetTable(new String[] { grp });
567 groupPanel.add(check);
571 boolean resettingTable = false;
573 synchronized void resetTable(String[] groupChanged)
575 if (resettingTable == true)
579 resettingTable = true;
580 typeWidth = new Hashtable<String, float[]>();
581 // TODO: change avWidth calculation to 'per-sequence' average and use long
583 float[] avWidth = null;
584 SequenceFeature[] tmpfeatures;
585 String group = null, type;
586 Vector<String> visibleChecks = new Vector<String>();
588 // Find out which features should be visible depending on which groups
589 // are selected / deselected
590 // and recompute average width ordering
591 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
594 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
595 .getSequenceFeatures();
596 if (tmpfeatures == null)
602 while (index < tmpfeatures.length)
604 group = tmpfeatures[index].featureGroup;
606 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
612 if (group == null || checkGroupState(group))
614 type = tmpfeatures[index].getType();
615 if (!visibleChecks.contains(type))
617 visibleChecks.addElement(type);
620 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
622 typeWidth.put(tmpfeatures[index].getType(),
623 avWidth = new float[3]);
627 avWidth = typeWidth.get(tmpfeatures[index].getType());
630 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
632 avWidth[1] += 1 + tmpfeatures[index].getBegin()
633 - tmpfeatures[index].getEnd();
637 avWidth[1] += 1 + tmpfeatures[index].getEnd()
638 - tmpfeatures[index].getBegin();
644 int fSize = visibleChecks.size();
645 Object[][] data = new Object[fSize][3];
648 if (fr.hasRenderOrder())
652 fr.findAllFeatures(groupChanged != null); // prod to update
653 // colourschemes. but don't
655 // First add the checks in the previous render order,
656 // in case the window has been closed and reopened
658 List<String> frl = fr.getRenderOrder();
659 for (int ro = frl.size() - 1; ro > -1; ro--)
663 if (!visibleChecks.contains(type))
668 data[dataIndex][0] = type;
669 data[dataIndex][1] = fr.getFeatureStyle(type);
670 data[dataIndex][2] = new Boolean(af.getViewport()
671 .getFeaturesDisplayed().isVisible(type));
673 visibleChecks.removeElement(type);
677 fSize = visibleChecks.size();
678 for (int i = 0; i < fSize; i++)
680 // These must be extra features belonging to the group
681 // which was just selected
682 type = visibleChecks.elementAt(i).toString();
683 data[dataIndex][0] = type;
685 data[dataIndex][1] = fr.getFeatureStyle(type);
686 if (data[dataIndex][1] == null)
688 // "Colour has been updated in another view!!"
689 fr.clearRenderOrder();
693 data[dataIndex][2] = new Boolean(true);
697 if (originalData == null)
699 originalData = new Object[data.length][3];
700 for (int i = 0; i < data.length; i++)
702 System.arraycopy(data[i], 0, originalData[i], 0, 3);
706 table.setModel(new FeatureTableModel(data));
707 table.getColumnModel().getColumn(0).setPreferredWidth(200);
709 if (groupPanel != null)
711 groupPanel.setLayout(new GridLayout(
712 fr.getFeatureGroupsSize() / 4 + 1, 4));
714 groupPanel.validate();
715 bigPanel.add(groupPanel, BorderLayout.NORTH);
718 updateFeatureRenderer(data, groupChanged != null);
719 resettingTable = false;
723 * reorder data based on the featureRenderers global priority list.
727 private void ensureOrder(Object[][] data)
729 boolean sort = false;
730 float[] order = new float[data.length];
731 for (int i = 0; i < order.length; i++)
733 order[i] = fr.getOrder(data[i][0].toString());
736 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
740 sort = sort || order[i - 1] > order[i];
745 jalview.util.QuickSort.sort(order, data);
751 JalviewFileChooser chooser = new JalviewFileChooser("fc",
752 "Sequence Feature Colours");
753 chooser.setFileView(new JalviewFileView());
754 chooser.setDialogTitle(MessageManager
755 .getString("label.load_feature_colours"));
756 chooser.setToolTipText(MessageManager.getString("action.load"));
758 int value = chooser.showOpenDialog(this);
760 if (value == JalviewFileChooser.APPROVE_OPTION)
762 File file = chooser.getSelectedFile();
766 InputStreamReader in = new InputStreamReader(new FileInputStream(
769 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
771 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
774 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
777 Color mincol = null, maxcol = null;
780 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
781 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
783 } catch (Exception e)
785 Cache.log.warn("Couldn't parse out graduated feature color.",
788 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
789 newcol.getMin(), newcol.getMax());
790 if (newcol.hasAutoScale())
792 gcol.setAutoScaled(newcol.getAutoScale());
794 if (newcol.hasColourByLabel())
796 gcol.setColourByLabel(newcol.getColourByLabel());
798 if (newcol.hasThreshold())
800 gcol.setThreshold(newcol.getThreshold());
802 if (newcol.getThreshType().length() > 0)
804 String ttyp = newcol.getThreshType();
805 if (ttyp.equalsIgnoreCase("ABOVE"))
807 gcol.setAboveThreshold(true);
809 if (ttyp.equalsIgnoreCase("BELOW"))
811 gcol.setBelowThreshold(true);
814 fr.setColour(name = newcol.getName(), gcol);
818 Color color = new Color(
819 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
820 fr.setColour(name = jucs.getColour(i).getName(),
821 new FeatureColour(color));
823 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
828 Object[][] data = ((FeatureTableModel) table.getModel())
831 updateFeatureRenderer(data, false);
834 } catch (Exception ex)
836 System.out.println("Error loading User Colour File\n" + ex);
843 JalviewFileChooser chooser = new JalviewFileChooser("fc",
844 "Sequence Feature Colours");
845 chooser.setFileView(new JalviewFileView());
846 chooser.setDialogTitle(MessageManager
847 .getString("label.save_feature_colours"));
848 chooser.setToolTipText(MessageManager.getString("action.save"));
850 int value = chooser.showSaveDialog(this);
852 if (value == JalviewFileChooser.APPROVE_OPTION)
854 String choice = chooser.getSelectedFile().getPath();
855 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
856 ucs.setSchemeName("Sequence Features");
859 PrintWriter out = new PrintWriter(new OutputStreamWriter(
860 new FileOutputStream(choice), "UTF-8"));
862 Set<String> fr_colours = fr.getAllFeatureColours();
863 Iterator<String> e = fr_colours.iterator();
864 float[] sortOrder = new float[fr_colours.size()];
865 String[] sortTypes = new String[fr_colours.size()];
869 sortTypes[i] = e.next();
870 sortOrder[i] = fr.getOrder(sortTypes[i]);
873 QuickSort.sort(sortOrder, sortTypes);
875 for (i = 0; i < sortTypes.length; i++)
877 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
878 col.setName(sortTypes[i]);
879 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
880 if (fcol.isSimpleColour())
882 col.setRGB(Format.getHexString(fcol.getColour()));
886 col.setRGB(Format.getHexString(fcol.getMaxColour()));
887 col.setMin(fcol.getMin());
888 col.setMax(fcol.getMax());
889 col.setMinRGB(jalview.util.Format.getHexString(fcol
891 col.setAutoScale(fcol.isAutoScaled());
892 col.setThreshold(fcol.getThreshold());
893 col.setColourByLabel(fcol.isColourByLabel());
894 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
895 .isBelowThreshold() ? "BELOW" : "NONE"));
901 } catch (Exception ex)
903 ex.printStackTrace();
908 public void invertSelection()
910 for (int i = 0; i < table.getRowCount(); i++)
912 Boolean value = (Boolean) table.getValueAt(i, 2);
914 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
918 public void orderByAvWidth()
920 if (table == null || table.getModel() == null)
924 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
925 float[] width = new float[data.length];
929 for (int i = 0; i < data.length; i++)
931 awidth = typeWidth.get(data[i][0]);
934 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
935 // weight - but have to make per
936 // sequence, too (awidth[2])
937 // if (width[i]==1) // hack to distinguish single width sequences.
949 boolean sort = false;
950 for (int i = 0; i < width.length; i++)
952 // awidth = (float[]) typeWidth.get(data[i][0]);
955 width[i] = fr.getOrder(data[i][0].toString());
958 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
963 width[i] /= max; // normalize
964 fr.setOrder(data[i][0].toString(), width[i]); // store for later
968 sort = sort || width[i - 1] > width[i];
973 jalview.util.QuickSort.sort(width, data);
974 // update global priority order
977 updateFeatureRenderer(data, false);
985 frame.setClosed(true);
986 } catch (Exception exe)
992 public void updateFeatureRenderer(Object[][] data)
994 updateFeatureRenderer(data, true);
998 * Update the priority order of features; only repaint if this changed the
999 * order of visible features
1004 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1006 if (fr.setFeaturePriority(data, visibleNew))
1008 af.alignPanel.paintAlignment(true);
1012 int selectedRow = -1;
1014 JTabbedPane tabbedPane = new JTabbedPane();
1016 BorderLayout borderLayout1 = new BorderLayout();
1018 BorderLayout borderLayout2 = new BorderLayout();
1020 BorderLayout borderLayout3 = new BorderLayout();
1022 JPanel bigPanel = new JPanel();
1024 BorderLayout borderLayout4 = new BorderLayout();
1026 JButton invert = new JButton();
1028 JPanel buttonPanel = new JPanel();
1030 JButton cancel = new JButton();
1032 JButton ok = new JButton();
1034 JButton loadColours = new JButton();
1036 JButton saveColours = new JButton();
1038 JPanel dasButtonPanel = new JPanel();
1040 JButton fetchDAS = new JButton();
1042 JButton saveDAS = new JButton();
1044 JButton cancelDAS = new JButton();
1046 JButton optimizeOrder = new JButton();
1048 JButton sortByScore = new JButton();
1050 JButton sortByDens = new JButton();
1052 JButton help = new JButton();
1054 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1056 private void jbInit() throws Exception
1058 this.setLayout(borderLayout1);
1059 settingsPane.setLayout(borderLayout2);
1060 dasSettingsPane.setLayout(borderLayout3);
1061 bigPanel.setLayout(borderLayout4);
1062 invert.setFont(JvSwingUtils.getLabelFont());
1063 invert.setText(MessageManager.getString("label.invert_selection"));
1064 invert.addActionListener(new ActionListener()
1067 public void actionPerformed(ActionEvent e)
1072 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1073 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1074 optimizeOrder.addActionListener(new ActionListener()
1077 public void actionPerformed(ActionEvent e)
1082 sortByScore.setFont(JvSwingUtils.getLabelFont());
1084 .setText(MessageManager.getString("label.seq_sort_by_score"));
1085 sortByScore.addActionListener(new ActionListener()
1088 public void actionPerformed(ActionEvent e)
1090 af.avc.sortAlignmentByFeatureScore(null);
1093 sortByDens.setFont(JvSwingUtils.getLabelFont());
1094 sortByDens.setText(MessageManager
1095 .getString("label.sequence_sort_by_density"));
1096 sortByDens.addActionListener(new ActionListener()
1099 public void actionPerformed(ActionEvent e)
1101 af.avc.sortAlignmentByFeatureDensity(null);
1104 help.setFont(JvSwingUtils.getLabelFont());
1105 help.setText(MessageManager.getString("action.help"));
1106 help.addActionListener(new ActionListener()
1109 public void actionPerformed(ActionEvent e)
1113 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1114 } catch (HelpSetException e1)
1116 e1.printStackTrace();
1120 help.setFont(JvSwingUtils.getLabelFont());
1121 help.setText(MessageManager.getString("action.help"));
1122 help.addActionListener(new ActionListener()
1125 public void actionPerformed(ActionEvent e)
1129 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1130 } catch (HelpSetException e1)
1132 e1.printStackTrace();
1136 cancel.setFont(JvSwingUtils.getLabelFont());
1137 cancel.setText(MessageManager.getString("action.cancel"));
1138 cancel.addActionListener(new ActionListener()
1141 public void actionPerformed(ActionEvent e)
1143 fr.setTransparency(originalTransparency);
1144 updateFeatureRenderer(originalData);
1148 ok.setFont(JvSwingUtils.getLabelFont());
1149 ok.setText(MessageManager.getString("action.ok"));
1150 ok.addActionListener(new ActionListener()
1153 public void actionPerformed(ActionEvent e)
1158 loadColours.setFont(JvSwingUtils.getLabelFont());
1159 loadColours.setText(MessageManager.getString("label.load_colours"));
1160 loadColours.addActionListener(new ActionListener()
1163 public void actionPerformed(ActionEvent e)
1168 saveColours.setFont(JvSwingUtils.getLabelFont());
1169 saveColours.setText(MessageManager.getString("label.save_colours"));
1170 saveColours.addActionListener(new ActionListener()
1173 public void actionPerformed(ActionEvent e)
1178 transparency.addChangeListener(new ChangeListener()
1181 public void stateChanged(ChangeEvent evt)
1183 fr.setTransparency((100 - transparency.getValue()) / 100f);
1184 af.alignPanel.paintAlignment(true);
1188 transparency.setMaximum(70);
1189 transparency.setToolTipText(MessageManager
1190 .getString("label.transparency_tip"));
1191 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1192 fetchDAS.addActionListener(new ActionListener()
1195 public void actionPerformed(ActionEvent e)
1197 fetchDAS_actionPerformed(e);
1200 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1201 saveDAS.addActionListener(new ActionListener()
1204 public void actionPerformed(ActionEvent e)
1206 saveDAS_actionPerformed(e);
1209 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1210 dasSettingsPane.setBorder(null);
1211 cancelDAS.setEnabled(false);
1212 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1213 cancelDAS.addActionListener(new ActionListener()
1216 public void actionPerformed(ActionEvent e)
1218 cancelDAS_actionPerformed(e);
1221 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1222 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1224 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1226 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1227 transbuttons.add(optimizeOrder);
1228 transbuttons.add(invert);
1229 transbuttons.add(sortByScore);
1230 transbuttons.add(sortByDens);
1231 transbuttons.add(help);
1232 JPanel sliderPanel = new JPanel();
1233 sliderPanel.add(transparency);
1234 transPanel.add(transparency);
1235 transPanel.add(transbuttons);
1236 buttonPanel.add(ok);
1237 buttonPanel.add(cancel);
1238 buttonPanel.add(loadColours);
1239 buttonPanel.add(saveColours);
1240 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1241 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1242 dasButtonPanel.add(fetchDAS);
1243 dasButtonPanel.add(cancelDAS);
1244 dasButtonPanel.add(saveDAS);
1245 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1246 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1249 public void fetchDAS_actionPerformed(ActionEvent e)
1251 fetchDAS.setEnabled(false);
1252 cancelDAS.setEnabled(true);
1253 dassourceBrowser.setGuiEnabled(false);
1254 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1255 .getSelectedSources();
1256 doDasFeatureFetch(selectedSources, true, true);
1260 * get the features from selectedSources for all or the current selection
1262 * @param selectedSources
1263 * @param checkDbRefs
1264 * @param promptFetchDbRefs
1266 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1267 boolean checkDbRefs, boolean promptFetchDbRefs)
1269 SequenceI[] dataset, seqs;
1271 AlignmentViewport vp = af.getViewport();
1272 if (vp.getSelectionGroup() != null
1273 && vp.getSelectionGroup().getSize() > 0)
1275 iSize = vp.getSelectionGroup().getSize();
1276 dataset = new SequenceI[iSize];
1277 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1281 iSize = vp.getAlignment().getHeight();
1282 seqs = vp.getAlignment().getSequencesArray();
1285 dataset = new SequenceI[iSize];
1286 for (int i = 0; i < iSize; i++)
1288 dataset[i] = seqs[i].getDatasetSequence();
1291 cancelDAS.setEnabled(true);
1292 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1293 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1294 af.getViewport().setShowSequenceFeatures(true);
1295 af.showSeqFeatures.setSelected(true);
1299 * blocking call to initialise the das source browser
1301 public void initDasSources()
1303 dassourceBrowser.initDasSources();
1307 * examine the current list of das sources and return any matching the given
1308 * nicknames in sources
1311 * Vector of Strings to resolve to DAS source nicknames.
1312 * @return sources that are present in source list.
1314 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1316 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1320 * get currently selected das sources. ensure you have called initDasSources
1321 * before calling this.
1323 * @return vector of selected das source nicknames
1325 public Vector<jalviewSourceI> getSelectedSources()
1327 return dassourceBrowser.getSelectedSources();
1331 * properly initialise DAS fetcher and then initiate a new thread to fetch
1332 * features from the named sources (rather than any turned on by default)
1336 * if true then runs in same thread, otherwise passes to the Swing
1339 public void fetchDasFeatures(Vector<String> sources, boolean block)
1342 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1343 .resolveSourceNicknames(sources);
1344 if (resolved.size() == 0)
1346 resolved = dassourceBrowser.getSelectedSources();
1348 if (resolved.size() > 0)
1350 final List<jalviewSourceI> dassources = resolved;
1351 fetchDAS.setEnabled(false);
1352 // cancelDAS.setEnabled(true); doDasFetch does this.
1353 Runnable fetcher = new Runnable()
1359 doDasFeatureFetch(dassources, true, false);
1369 SwingUtilities.invokeLater(fetcher);
1374 public void saveDAS_actionPerformed(ActionEvent e)
1377 .saveProperties(jalview.bin.Cache.applicationProperties);
1380 public void complete()
1382 fetchDAS.setEnabled(true);
1383 cancelDAS.setEnabled(false);
1384 dassourceBrowser.setGuiEnabled(true);
1388 public void cancelDAS_actionPerformed(ActionEvent e)
1390 if (dasFeatureFetcher != null)
1392 dasFeatureFetcher.cancel();
1397 public void noDasSourceActive()
1401 .showInternalConfirmDialog(
1404 .getString("label.no_das_sources_selected_warn"),
1406 .getString("label.no_das_sources_selected_title"),
1407 JvOptionPane.DEFAULT_OPTION,
1408 JvOptionPane.INFORMATION_MESSAGE);
1411 // ///////////////////////////////////////////////////////////////////////
1412 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1413 // ///////////////////////////////////////////////////////////////////////
1414 class FeatureTableModel extends AbstractTableModel
1416 FeatureTableModel(Object[][] data)
1421 private String[] columnNames = {
1422 MessageManager.getString("label.feature_type"),
1423 MessageManager.getString("action.colour"),
1424 MessageManager.getString("label.display") };
1426 private Object[][] data;
1428 public Object[][] getData()
1433 public void setData(Object[][] data)
1439 public int getColumnCount()
1441 return columnNames.length;
1444 public Object[] getRow(int row)
1450 public int getRowCount()
1456 public String getColumnName(int col)
1458 return columnNames[col];
1462 public Object getValueAt(int row, int col)
1464 return data[row][col];
1468 public Class getColumnClass(int c)
1470 return getValueAt(0, c).getClass();
1474 public boolean isCellEditable(int row, int col)
1476 return col == 0 ? false : true;
1480 public void setValueAt(Object value, int row, int col)
1482 data[row][col] = value;
1483 fireTableCellUpdated(row, col);
1484 updateFeatureRenderer(data);
1489 class ColorRenderer extends JLabel implements TableCellRenderer
1491 javax.swing.border.Border unselectedBorder = null;
1493 javax.swing.border.Border selectedBorder = null;
1495 final String baseTT = "Click to edit, right/apple click for menu.";
1497 public ColorRenderer()
1499 setOpaque(true); // MUST do this for background to show up.
1500 setHorizontalTextPosition(SwingConstants.CENTER);
1501 setVerticalTextPosition(SwingConstants.CENTER);
1505 public Component getTableCellRendererComponent(JTable tbl,
1506 Object color, boolean isSelected, boolean hasFocus, int row,
1509 FeatureColourI cellColour = (FeatureColourI) color;
1510 // JLabel comp = new JLabel();
1514 // setBounds(getBounds());
1516 setToolTipText(baseTT);
1517 setBackground(tbl.getBackground());
1518 if (!cellColour.isSimpleColour())
1520 Rectangle cr = tbl.getCellRect(row, column, false);
1521 FeatureSettings.renderGraduatedColor(this, cellColour,
1522 (int) cr.getWidth(), (int) cr.getHeight());
1529 newColor = cellColour.getColour();
1530 setBackground(newColor);
1534 if (selectedBorder == null)
1536 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1537 tbl.getSelectionBackground());
1539 setBorder(selectedBorder);
1543 if (unselectedBorder == null)
1545 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1546 tbl.getBackground());
1548 setBorder(unselectedBorder);
1556 * update comp using rendering settings from gcol
1561 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1563 int w = comp.getWidth(), h = comp.getHeight();
1566 w = (int) comp.getPreferredSize().getWidth();
1567 h = (int) comp.getPreferredSize().getHeight();
1574 renderGraduatedColor(comp, gcol, w, h);
1577 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1580 boolean thr = false;
1583 if (gcol.isAboveThreshold())
1587 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1589 if (gcol.isBelowThreshold())
1593 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1595 if (gcol.isColourByLabel())
1597 tt = "Coloured by label text. " + tt;
1607 Color newColor = gcol.getMaxColour();
1608 comp.setBackground(newColor);
1609 // System.err.println("Width is " + w / 2);
1610 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1611 comp.setIcon(ficon);
1612 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1613 // + newColor.getGreen() + ", " + newColor.getBlue()
1614 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1615 // + ", " + minCol.getBlue() + ")");
1617 comp.setHorizontalAlignment(SwingConstants.CENTER);
1619 if (tt.length() > 0)
1621 if (comp.getToolTipText() == null)
1623 comp.setToolTipText(tt);
1627 comp.setToolTipText(tt + " " + comp.getToolTipText());
1633 class FeatureIcon implements Icon
1635 FeatureColourI gcol;
1639 boolean midspace = false;
1641 int width = 50, height = 20;
1643 int s1, e1; // start and end of midpoint band for thresholded symbol
1645 Color mpcolour = Color.white;
1647 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1667 public int getIconWidth()
1673 public int getIconHeight()
1679 public void paintIcon(Component c, Graphics g, int x, int y)
1682 if (gcol.isColourByLabel())
1685 g.fillRect(0, 0, width, height);
1686 // need an icon here.
1687 g.setColor(gcol.getMaxColour());
1689 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1691 // g.setFont(g.getFont().deriveFont(
1692 // AffineTransform.getScaleInstance(
1693 // width/g.getFontMetrics().stringWidth("Label"),
1694 // height/g.getFontMetrics().getHeight())));
1696 g.drawString(MessageManager.getString("label.label"), 0, 0);
1701 Color minCol = gcol.getMinColour();
1703 g.fillRect(0, 0, s1, height);
1706 g.setColor(Color.white);
1707 g.fillRect(s1, 0, e1 - s1, height);
1709 g.setColor(gcol.getMaxColour());
1710 g.fillRect(0, e1, width - e1, height);
1715 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1720 FeatureColourI currentColor;
1722 FeatureColourChooser chooser;
1728 JColorChooser colorChooser;
1732 protected static final String EDIT = "edit";
1734 int selectedRow = 0;
1736 public ColorEditor(FeatureSettings me)
1739 // Set up the editor (from the table's point of view),
1740 // which is a button.
1741 // This button brings up the color chooser dialog,
1742 // which is the editor from the user's point of view.
1743 button = new JButton();
1744 button.setActionCommand(EDIT);
1745 button.addActionListener(this);
1746 button.setBorderPainted(false);
1747 // Set up the dialog that the button brings up.
1748 colorChooser = new JColorChooser();
1749 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1750 colorChooser, this, // OK button handler
1751 null); // no CANCEL button handler
1755 * Handles events from the editor button and from the dialog's OK button.
1758 public void actionPerformed(ActionEvent e)
1761 if (EDIT.equals(e.getActionCommand()))
1763 // The user has clicked the cell, so
1764 // bring up the dialog.
1765 if (currentColor.isSimpleColour())
1767 // bring up simple color chooser
1768 button.setBackground(currentColor.getColour());
1769 colorChooser.setColor(currentColor.getColour());
1770 dialog.setVisible(true);
1774 // bring up graduated chooser.
1775 chooser = new FeatureColourChooser(me.fr, type);
1776 chooser.setRequestFocusEnabled(true);
1777 chooser.requestFocus();
1778 chooser.addActionListener(this);
1780 // Make the renderer reappear.
1781 fireEditingStopped();
1785 { // User pressed dialog's "OK" button.
1786 if (currentColor.isSimpleColour())
1788 currentColor = new FeatureColour(colorChooser.getColor());
1792 currentColor = chooser.getLastColour();
1794 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1795 fireEditingStopped();
1796 me.table.validate();
1800 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1802 public Object getCellEditorValue()
1804 return currentColor;
1807 // Implement the one method defined by TableCellEditor.
1809 public Component getTableCellEditorComponent(JTable table, Object value,
1810 boolean isSelected, int row, int column)
1812 currentColor = (FeatureColourI) value;
1813 this.selectedRow = row;
1814 type = me.table.getValueAt(row, 0).toString();
1815 button.setOpaque(true);
1816 button.setBackground(me.getBackground());
1817 if (!currentColor.isSimpleColour())
1819 JLabel btn = new JLabel();
1820 btn.setSize(button.getSize());
1821 FeatureSettings.renderGraduatedColor(btn, currentColor);
1822 button.setBackground(btn.getBackground());
1823 button.setIcon(btn.getIcon());
1824 button.setText(btn.getText());
1829 button.setIcon(null);
1830 button.setBackground(currentColor.getColour());