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.schemabinding.version2.JalviewUserColours;
31 import jalview.schemes.FeatureColour;
32 import jalview.util.Format;
33 import jalview.util.MessageManager;
34 import jalview.util.Platform;
35 import jalview.util.QuickSort;
36 import jalview.viewmodel.AlignmentViewport;
37 import jalview.ws.dbsources.das.api.jalviewSourceI;
39 import java.awt.BorderLayout;
40 import java.awt.Color;
41 import java.awt.Component;
43 import java.awt.Graphics;
44 import java.awt.GridLayout;
45 import java.awt.Rectangle;
46 import java.awt.event.ActionEvent;
47 import java.awt.event.ActionListener;
48 import java.awt.event.ItemEvent;
49 import java.awt.event.ItemListener;
50 import java.awt.event.MouseAdapter;
51 import java.awt.event.MouseEvent;
52 import java.awt.event.MouseMotionAdapter;
53 import java.beans.PropertyChangeEvent;
54 import java.beans.PropertyChangeListener;
56 import java.io.FileInputStream;
57 import java.io.FileOutputStream;
58 import java.io.InputStreamReader;
59 import java.io.OutputStreamWriter;
60 import java.io.PrintWriter;
61 import java.util.Arrays;
62 import java.util.Hashtable;
63 import java.util.Iterator;
64 import java.util.List;
67 import java.util.Vector;
69 import javax.help.HelpSetException;
70 import javax.swing.AbstractCellEditor;
71 import javax.swing.BorderFactory;
72 import javax.swing.Icon;
73 import javax.swing.JButton;
74 import javax.swing.JCheckBox;
75 import javax.swing.JCheckBoxMenuItem;
76 import javax.swing.JColorChooser;
77 import javax.swing.JDialog;
78 import javax.swing.JInternalFrame;
79 import javax.swing.JLabel;
80 import javax.swing.JLayeredPane;
81 import javax.swing.JMenuItem;
82 import javax.swing.JOptionPane;
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 (SwingUtilities.isRightMouseButton(evt))
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 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
186 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
188 (String) table.getValueAt(selectedRow, 0));
192 // isPopupTrigger fires on mouseReleased on Mac
194 public void mouseReleased(MouseEvent evt)
196 selectedRow = table.rowAtPoint(evt.getPoint());
197 if (evt.isPopupTrigger())
199 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
200 table.getValueAt(selectedRow, 1), fr.getMinMax(),
201 evt.getX(), evt.getY());
206 table.addMouseMotionListener(new MouseMotionAdapter()
209 public void mouseDragged(MouseEvent evt)
211 int newRow = table.rowAtPoint(evt.getPoint());
212 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
215 * reposition 'selectedRow' to 'newRow' (the dragged to location)
216 * this could be more than one row away for a very fast drag action
217 * so just swap it with adjacent rows until we get it there
219 Object[][] data = ((FeatureTableModel) table.getModel())
221 int direction = newRow < selectedRow ? -1 : 1;
222 for (int i = selectedRow; i != newRow; i += direction)
224 Object[] temp = data[i];
225 data[i] = data[i + direction];
226 data[i + direction] = temp;
228 updateFeatureRenderer(data);
230 selectedRow = newRow;
234 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
235 // MessageManager.getString("label.feature_settings_click_drag")));
236 scrollPane.setViewportView(table);
238 dassourceBrowser = new DasSourceBrowser(this);
239 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
241 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
243 fr.findAllFeatures(true); // display everything!
246 discoverAllFeatureData();
247 final PropertyChangeListener change;
248 final FeatureSettings fs = this;
249 fr.addPropertyChangeListener(change = new PropertyChangeListener()
252 public void propertyChange(PropertyChangeEvent evt)
254 if (!fs.resettingTable && !fs.handlingUpdate)
256 fs.handlingUpdate = true;
257 fs.resetTable(null); // new groups may be added with new seuqence
258 // feature types only
259 fs.handlingUpdate = false;
265 frame = new JInternalFrame();
266 frame.setContentPane(this);
267 if (Platform.isAMac())
269 Desktop.addInternalFrame(frame,
270 MessageManager.getString("label.sequence_feature_settings"),
275 Desktop.addInternalFrame(frame,
276 MessageManager.getString("label.sequence_feature_settings"),
280 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
283 public void internalFrameClosed(
284 javax.swing.event.InternalFrameEvent evt)
286 fr.removePropertyChangeListener(change);
287 dassourceBrowser.fs = null;
290 frame.setLayer(JLayeredPane.PALETTE_LAYER);
293 protected void popupSort(final int selectedRow, final String type,
294 final Object typeCol, final Map<String, float[][]> minmax, int x,
297 final FeatureColourI featureColour = (FeatureColourI) typeCol;
299 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
300 "label.settings_for_param", new String[] { type }));
301 JMenuItem scr = new JMenuItem(
302 MessageManager.getString("label.sort_by_score"));
304 final FeatureSettings me = this;
305 scr.addActionListener(new ActionListener()
309 public void actionPerformed(ActionEvent e)
311 me.af.avc.sortAlignmentByFeatureScore(Arrays
312 .asList(new String[] { type }));
316 JMenuItem dens = new JMenuItem(
317 MessageManager.getString("label.sort_by_density"));
318 dens.addActionListener(new ActionListener()
322 public void actionPerformed(ActionEvent e)
324 me.af.avc.sortAlignmentByFeatureDensity(Arrays
325 .asList(new String[] { type }));
332 final float[][] typeMinMax = minmax.get(type);
334 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
335 * this is broken at the moment and isn't that useful anyway!
336 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
339 * public void actionPerformed(ActionEvent e) {
340 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
341 * null); } else { minmax.put(type, typeMinMax); } }
347 if (typeMinMax != null && typeMinMax[0] != null)
349 // if (table.getValueAt(row, column));
350 // graduated colourschemes for those where minmax exists for the
351 // positional features
352 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
354 mxcol.setSelected(!featureColour.isSimpleColour());
356 mxcol.addActionListener(new ActionListener()
358 JColorChooser colorChooser;
361 public void actionPerformed(ActionEvent e)
363 if (e.getSource() == mxcol)
365 if (featureColour.isSimpleColour())
367 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
369 fc.addActionListener(this);
373 // bring up simple color chooser
374 colorChooser = new JColorChooser();
375 JDialog dialog = JColorChooser.createDialog(me,
376 "Select new Colour", true, // modal
377 colorChooser, this, // OK button handler
378 null); // no CANCEL button handler
379 colorChooser.setColor(featureColour.getMaxColour());
380 dialog.setVisible(true);
385 if (e.getSource() instanceof FeatureColourChooser)
387 FeatureColourChooser fc = (FeatureColourChooser) e
389 table.setValueAt(fc.getLastColour(), selectedRow, 1);
394 // probably the color chooser!
396 new FeatureColour(colorChooser.getColor()),
399 me.updateFeatureRenderer(
400 ((FeatureTableModel) table.getModel()).getData(),
409 JMenuItem selCols = new JMenuItem(
410 MessageManager.getString("label.select_columns_containing"));
411 selCols.addActionListener(new ActionListener()
414 public void actionPerformed(ActionEvent arg0)
416 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
420 JMenuItem clearCols = new JMenuItem(
421 MessageManager.getString("label.select_columns_not_containing"));
422 clearCols.addActionListener(new ActionListener()
425 public void actionPerformed(ActionEvent arg0)
427 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
431 JMenuItem hideCols = new JMenuItem(
432 MessageManager.getString("label.hide_columns_containing"));
433 hideCols.addActionListener(new ActionListener()
436 public void actionPerformed(ActionEvent arg0)
438 fr.ap.alignFrame.hideFeatureColumns(type, true);
441 JMenuItem hideOtherCols = new JMenuItem(
442 MessageManager.getString("label.hide_columns_not_containing"));
443 hideOtherCols.addActionListener(new ActionListener()
446 public void actionPerformed(ActionEvent arg0)
448 fr.ap.alignFrame.hideFeatureColumns(type, false);
454 men.add(hideOtherCols);
455 men.show(table, x, y);
459 * true when Feature Settings are updating from feature renderer
461 private boolean handlingUpdate = false;
464 * contains a float[3] for each feature type string. created by setTableData
466 Map<String, float[]> typeWidth = null;
469 synchronized public void discoverAllFeatureData()
471 Vector<String> allFeatures = new Vector<String>();
472 Vector<String> allGroups = new Vector<String>();
473 SequenceFeature[] tmpfeatures;
475 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
477 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
478 .getSequenceFeatures();
479 if (tmpfeatures == null)
485 while (index < tmpfeatures.length)
487 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
493 if (tmpfeatures[index].getFeatureGroup() != null)
495 group = tmpfeatures[index].featureGroup;
496 if (!allGroups.contains(group))
498 allGroups.addElement(group);
499 checkGroupState(group);
503 if (!allFeatures.contains(tmpfeatures[index].getType()))
505 allFeatures.addElement(tmpfeatures[index].getType());
517 * Synchronise gui group list and check visibility of group
520 * @return true if group is visible
522 private boolean checkGroupState(String group)
524 boolean visible = fr.checkGroupVisibility(group, true);
526 if (groupPanel == null)
528 groupPanel = new JPanel();
531 boolean alreadyAdded = false;
532 for (int g = 0; g < groupPanel.getComponentCount(); g++)
534 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
537 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
547 final String grp = group;
548 final JCheckBox check = new JCheckBox(group, visible);
549 check.setFont(new Font("Serif", Font.BOLD, 12));
550 check.addItemListener(new ItemListener()
553 public void itemStateChanged(ItemEvent evt)
555 fr.setGroupVisibility(check.getText(), check.isSelected());
556 af.alignPanel.getSeqPanel().seqCanvas.repaint();
557 if (af.alignPanel.overviewPanel != null)
559 af.alignPanel.overviewPanel.updateOverviewImage();
562 resetTable(new String[] { grp });
565 groupPanel.add(check);
569 boolean resettingTable = false;
571 synchronized void resetTable(String[] groupChanged)
573 if (resettingTable == true)
577 resettingTable = true;
578 typeWidth = new Hashtable<String, float[]>();
579 // TODO: change avWidth calculation to 'per-sequence' average and use long
581 float[] avWidth = null;
582 SequenceFeature[] tmpfeatures;
583 String group = null, type;
584 Vector<String> visibleChecks = new Vector<String>();
586 // Find out which features should be visible depending on which groups
587 // are selected / deselected
588 // and recompute average width ordering
589 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
592 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
593 .getSequenceFeatures();
594 if (tmpfeatures == null)
600 while (index < tmpfeatures.length)
602 group = tmpfeatures[index].featureGroup;
604 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
610 if (group == null || checkGroupState(group))
612 type = tmpfeatures[index].getType();
613 if (!visibleChecks.contains(type))
615 visibleChecks.addElement(type);
618 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
620 typeWidth.put(tmpfeatures[index].getType(),
621 avWidth = new float[3]);
625 avWidth = typeWidth.get(tmpfeatures[index].getType());
628 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
630 avWidth[1] += 1 + tmpfeatures[index].getBegin()
631 - tmpfeatures[index].getEnd();
635 avWidth[1] += 1 + tmpfeatures[index].getEnd()
636 - tmpfeatures[index].getBegin();
642 int fSize = visibleChecks.size();
643 Object[][] data = new Object[fSize][3];
646 if (fr.hasRenderOrder())
650 fr.findAllFeatures(groupChanged != null); // prod to update
651 // colourschemes. but don't
653 // First add the checks in the previous render order,
654 // in case the window has been closed and reopened
656 List<String> frl = fr.getRenderOrder();
657 for (int ro = frl.size() - 1; ro > -1; ro--)
661 if (!visibleChecks.contains(type))
666 data[dataIndex][0] = type;
667 data[dataIndex][1] = fr.getFeatureStyle(type);
668 data[dataIndex][2] = new Boolean(af.getViewport()
669 .getFeaturesDisplayed().isVisible(type));
671 visibleChecks.removeElement(type);
675 fSize = visibleChecks.size();
676 for (int i = 0; i < fSize; i++)
678 // These must be extra features belonging to the group
679 // which was just selected
680 type = visibleChecks.elementAt(i).toString();
681 data[dataIndex][0] = type;
683 data[dataIndex][1] = fr.getFeatureStyle(type);
684 if (data[dataIndex][1] == null)
686 // "Colour has been updated in another view!!"
687 fr.clearRenderOrder();
691 data[dataIndex][2] = new Boolean(true);
695 if (originalData == null)
697 originalData = new Object[data.length][3];
698 for (int i = 0; i < data.length; i++)
700 System.arraycopy(data[i], 0, originalData[i], 0, 3);
704 table.setModel(new FeatureTableModel(data));
705 table.getColumnModel().getColumn(0).setPreferredWidth(200);
707 if (groupPanel != null)
709 groupPanel.setLayout(new GridLayout(
710 fr.getFeatureGroupsSize() / 4 + 1, 4));
712 groupPanel.validate();
713 bigPanel.add(groupPanel, BorderLayout.NORTH);
716 updateFeatureRenderer(data, groupChanged != null);
717 resettingTable = false;
721 * reorder data based on the featureRenderers global priority list.
725 private void ensureOrder(Object[][] data)
727 boolean sort = false;
728 float[] order = new float[data.length];
729 for (int i = 0; i < order.length; i++)
731 order[i] = fr.getOrder(data[i][0].toString());
734 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
738 sort = sort || order[i - 1] > order[i];
743 jalview.util.QuickSort.sort(order, data);
749 JalviewFileChooser chooser = new JalviewFileChooser(
750 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
751 new String[] { "fc" },
752 new String[] { "Sequence Feature Colours" },
753 "Sequence Feature Colours");
754 chooser.setFileView(new jalview.io.JalviewFileView());
755 chooser.setDialogTitle(MessageManager
756 .getString("label.load_feature_colours"));
757 chooser.setToolTipText(MessageManager.getString("action.load"));
759 int value = chooser.showOpenDialog(this);
761 if (value == JalviewFileChooser.APPROVE_OPTION)
763 File file = chooser.getSelectedFile();
767 InputStreamReader in = new InputStreamReader(new FileInputStream(
770 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
772 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
775 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
778 Color mincol = null, maxcol = null;
781 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
782 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
784 } catch (Exception e)
786 Cache.log.warn("Couldn't parse out graduated feature color.",
789 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
790 newcol.getMin(), newcol.getMax());
791 if (newcol.hasAutoScale())
793 gcol.setAutoScaled(newcol.getAutoScale());
795 if (newcol.hasColourByLabel())
797 gcol.setColourByLabel(newcol.getColourByLabel());
799 if (newcol.hasThreshold())
801 gcol.setThreshold(newcol.getThreshold());
803 if (newcol.getThreshType().length() > 0)
805 String ttyp = newcol.getThreshType();
806 if (ttyp.equalsIgnoreCase("ABOVE"))
808 gcol.setAboveThreshold(true);
810 if (ttyp.equalsIgnoreCase("BELOW"))
812 gcol.setBelowThreshold(true);
815 fr.setColour(name = newcol.getName(), gcol);
819 Color color = new Color(
820 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
821 fr.setColour(name = jucs.getColour(i).getName(),
822 new FeatureColour(color));
824 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
829 Object[][] data = ((FeatureTableModel) table.getModel())
832 updateFeatureRenderer(data, false);
835 } catch (Exception ex)
837 System.out.println("Error loading User Colour File\n" + ex);
844 JalviewFileChooser chooser = new JalviewFileChooser(
845 Cache.getProperty("LAST_DIRECTORY"),
846 new String[] { "fc" },
847 new String[] { "Sequence Feature Colours" },
848 "Sequence Feature Colours");
849 chooser.setFileView(new jalview.io.JalviewFileView());
850 chooser.setDialogTitle(MessageManager
851 .getString("label.save_feature_colours"));
852 chooser.setToolTipText(MessageManager.getString("action.save"));
854 int value = chooser.showSaveDialog(this);
856 if (value == JalviewFileChooser.APPROVE_OPTION)
858 String choice = chooser.getSelectedFile().getPath();
859 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
860 ucs.setSchemeName("Sequence Features");
863 PrintWriter out = new PrintWriter(new OutputStreamWriter(
864 new FileOutputStream(choice), "UTF-8"));
866 Set<String> fr_colours = fr.getAllFeatureColours();
867 Iterator<String> e = fr_colours.iterator();
868 float[] sortOrder = new float[fr_colours.size()];
869 String[] sortTypes = new String[fr_colours.size()];
873 sortTypes[i] = e.next();
874 sortOrder[i] = fr.getOrder(sortTypes[i]);
877 QuickSort.sort(sortOrder, sortTypes);
879 for (i = 0; i < sortTypes.length; i++)
881 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
882 col.setName(sortTypes[i]);
883 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
884 if (fcol.isSimpleColour())
886 col.setRGB(Format.getHexString(fcol.getColour()));
890 col.setRGB(Format.getHexString(fcol.getMaxColour()));
891 col.setMin(fcol.getMin());
892 col.setMax(fcol.getMax());
893 col.setMinRGB(jalview.util.Format.getHexString(fcol
895 col.setAutoScale(fcol.isAutoScaled());
896 col.setThreshold(fcol.getThreshold());
897 col.setColourByLabel(fcol.isColourByLabel());
898 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
899 .isBelowThreshold() ? "BELOW" : "NONE"));
905 } catch (Exception ex)
907 ex.printStackTrace();
912 public void invertSelection()
914 for (int i = 0; i < table.getRowCount(); i++)
916 Boolean value = (Boolean) table.getValueAt(i, 2);
918 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
922 public void orderByAvWidth()
924 if (table == null || table.getModel() == null)
928 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
929 float[] width = new float[data.length];
933 for (int i = 0; i < data.length; i++)
935 awidth = typeWidth.get(data[i][0]);
938 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
939 // weight - but have to make per
940 // sequence, too (awidth[2])
941 // if (width[i]==1) // hack to distinguish single width sequences.
953 boolean sort = false;
954 for (int i = 0; i < width.length; i++)
956 // awidth = (float[]) typeWidth.get(data[i][0]);
959 width[i] = fr.getOrder(data[i][0].toString());
962 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
967 width[i] /= max; // normalize
968 fr.setOrder(data[i][0].toString(), width[i]); // store for later
972 sort = sort || width[i - 1] > width[i];
977 jalview.util.QuickSort.sort(width, data);
978 // update global priority order
981 updateFeatureRenderer(data, false);
989 frame.setClosed(true);
990 } catch (Exception exe)
996 public void updateFeatureRenderer(Object[][] data)
998 updateFeatureRenderer(data, true);
1002 * Update the priority order of features; only repaint if this changed the
1003 * order of visible features
1008 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1010 if (fr.setFeaturePriority(data, visibleNew))
1012 af.alignPanel.paintAlignment(true);
1016 int selectedRow = -1;
1018 JTabbedPane tabbedPane = new JTabbedPane();
1020 BorderLayout borderLayout1 = new BorderLayout();
1022 BorderLayout borderLayout2 = new BorderLayout();
1024 BorderLayout borderLayout3 = new BorderLayout();
1026 JPanel bigPanel = new JPanel();
1028 BorderLayout borderLayout4 = new BorderLayout();
1030 JButton invert = new JButton();
1032 JPanel buttonPanel = new JPanel();
1034 JButton cancel = new JButton();
1036 JButton ok = new JButton();
1038 JButton loadColours = new JButton();
1040 JButton saveColours = new JButton();
1042 JPanel dasButtonPanel = new JPanel();
1044 JButton fetchDAS = new JButton();
1046 JButton saveDAS = new JButton();
1048 JButton cancelDAS = new JButton();
1050 JButton optimizeOrder = new JButton();
1052 JButton sortByScore = new JButton();
1054 JButton sortByDens = new JButton();
1056 JButton help = new JButton();
1058 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1060 private void jbInit() throws Exception
1062 this.setLayout(borderLayout1);
1063 settingsPane.setLayout(borderLayout2);
1064 dasSettingsPane.setLayout(borderLayout3);
1065 bigPanel.setLayout(borderLayout4);
1066 invert.setFont(JvSwingUtils.getLabelFont());
1067 invert.setText(MessageManager.getString("label.invert_selection"));
1068 invert.addActionListener(new ActionListener()
1071 public void actionPerformed(ActionEvent e)
1076 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1077 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1078 optimizeOrder.addActionListener(new ActionListener()
1081 public void actionPerformed(ActionEvent e)
1086 sortByScore.setFont(JvSwingUtils.getLabelFont());
1088 .setText(MessageManager.getString("label.seq_sort_by_score"));
1089 sortByScore.addActionListener(new ActionListener()
1092 public void actionPerformed(ActionEvent e)
1094 af.avc.sortAlignmentByFeatureScore(null);
1097 sortByDens.setFont(JvSwingUtils.getLabelFont());
1098 sortByDens.setText(MessageManager
1099 .getString("label.sequence_sort_by_density"));
1100 sortByDens.addActionListener(new ActionListener()
1103 public void actionPerformed(ActionEvent e)
1105 af.avc.sortAlignmentByFeatureDensity(null);
1108 help.setFont(JvSwingUtils.getLabelFont());
1109 help.setText(MessageManager.getString("action.help"));
1110 help.addActionListener(new ActionListener()
1113 public void actionPerformed(ActionEvent e)
1117 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1118 } catch (HelpSetException e1)
1120 e1.printStackTrace();
1124 help.setFont(JvSwingUtils.getLabelFont());
1125 help.setText(MessageManager.getString("action.help"));
1126 help.addActionListener(new ActionListener()
1129 public void actionPerformed(ActionEvent e)
1133 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1134 } catch (HelpSetException e1)
1136 e1.printStackTrace();
1140 cancel.setFont(JvSwingUtils.getLabelFont());
1141 cancel.setText(MessageManager.getString("action.cancel"));
1142 cancel.addActionListener(new ActionListener()
1145 public void actionPerformed(ActionEvent e)
1147 fr.setTransparency(originalTransparency);
1148 updateFeatureRenderer(originalData);
1152 ok.setFont(JvSwingUtils.getLabelFont());
1153 ok.setText(MessageManager.getString("action.ok"));
1154 ok.addActionListener(new ActionListener()
1157 public void actionPerformed(ActionEvent e)
1162 loadColours.setFont(JvSwingUtils.getLabelFont());
1163 loadColours.setText(MessageManager.getString("label.load_colours"));
1164 loadColours.addActionListener(new ActionListener()
1167 public void actionPerformed(ActionEvent e)
1172 saveColours.setFont(JvSwingUtils.getLabelFont());
1173 saveColours.setText(MessageManager.getString("label.save_colours"));
1174 saveColours.addActionListener(new ActionListener()
1177 public void actionPerformed(ActionEvent e)
1182 transparency.addChangeListener(new ChangeListener()
1185 public void stateChanged(ChangeEvent evt)
1187 fr.setTransparency((100 - transparency.getValue()) / 100f);
1188 af.alignPanel.paintAlignment(true);
1192 transparency.setMaximum(70);
1193 transparency.setToolTipText(MessageManager
1194 .getString("label.transparency_tip"));
1195 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1196 fetchDAS.addActionListener(new ActionListener()
1199 public void actionPerformed(ActionEvent e)
1201 fetchDAS_actionPerformed(e);
1204 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1205 saveDAS.addActionListener(new ActionListener()
1208 public void actionPerformed(ActionEvent e)
1210 saveDAS_actionPerformed(e);
1213 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1214 dasSettingsPane.setBorder(null);
1215 cancelDAS.setEnabled(false);
1216 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1217 cancelDAS.addActionListener(new ActionListener()
1220 public void actionPerformed(ActionEvent e)
1222 cancelDAS_actionPerformed(e);
1225 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1226 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1228 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1230 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1231 transbuttons.add(optimizeOrder);
1232 transbuttons.add(invert);
1233 transbuttons.add(sortByScore);
1234 transbuttons.add(sortByDens);
1235 transbuttons.add(help);
1236 JPanel sliderPanel = new JPanel();
1237 sliderPanel.add(transparency);
1238 transPanel.add(transparency);
1239 transPanel.add(transbuttons);
1240 buttonPanel.add(ok);
1241 buttonPanel.add(cancel);
1242 buttonPanel.add(loadColours);
1243 buttonPanel.add(saveColours);
1244 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1245 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1246 dasButtonPanel.add(fetchDAS);
1247 dasButtonPanel.add(cancelDAS);
1248 dasButtonPanel.add(saveDAS);
1249 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1250 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1253 public void fetchDAS_actionPerformed(ActionEvent e)
1255 fetchDAS.setEnabled(false);
1256 cancelDAS.setEnabled(true);
1257 dassourceBrowser.setGuiEnabled(false);
1258 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1259 .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<String> 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<String> 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 tbl,
1510 Object color, boolean isSelected, boolean hasFocus, int row,
1513 FeatureColourI cellColour = (FeatureColourI) color;
1514 // JLabel comp = new JLabel();
1518 // setBounds(getBounds());
1520 setToolTipText(baseTT);
1521 setBackground(tbl.getBackground());
1522 if (!cellColour.isSimpleColour())
1524 Rectangle cr = tbl.getCellRect(row, column, false);
1525 FeatureSettings.renderGraduatedColor(this, cellColour,
1526 (int) cr.getWidth(), (int) cr.getHeight());
1533 newColor = cellColour.getColour();
1534 setBackground(newColor);
1538 if (selectedBorder == null)
1540 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1541 tbl.getSelectionBackground());
1543 setBorder(selectedBorder);
1547 if (unselectedBorder == null)
1549 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1550 tbl.getBackground());
1552 setBorder(unselectedBorder);
1560 * update comp using rendering settings from gcol
1565 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1567 int w = comp.getWidth(), h = comp.getHeight();
1570 w = (int) comp.getPreferredSize().getWidth();
1571 h = (int) comp.getPreferredSize().getHeight();
1578 renderGraduatedColor(comp, gcol, w, h);
1581 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1584 boolean thr = false;
1587 if (gcol.isAboveThreshold())
1591 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1593 if (gcol.isBelowThreshold())
1597 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1599 if (gcol.isColourByLabel())
1601 tt = "Coloured by label text. " + tt;
1611 Color newColor = gcol.getMaxColour();
1612 comp.setBackground(newColor);
1613 // System.err.println("Width is " + w / 2);
1614 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1615 comp.setIcon(ficon);
1616 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1617 // + newColor.getGreen() + ", " + newColor.getBlue()
1618 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1619 // + ", " + minCol.getBlue() + ")");
1621 comp.setHorizontalAlignment(SwingConstants.CENTER);
1623 if (tt.length() > 0)
1625 if (comp.getToolTipText() == null)
1627 comp.setToolTipText(tt);
1631 comp.setToolTipText(tt + " " + comp.getToolTipText());
1637 class FeatureIcon implements Icon
1639 FeatureColourI gcol;
1643 boolean midspace = false;
1645 int width = 50, height = 20;
1647 int s1, e1; // start and end of midpoint band for thresholded symbol
1649 Color mpcolour = Color.white;
1651 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1671 public int getIconWidth()
1677 public int getIconHeight()
1683 public void paintIcon(Component c, Graphics g, int x, int y)
1686 if (gcol.isColourByLabel())
1689 g.fillRect(0, 0, width, height);
1690 // need an icon here.
1691 g.setColor(gcol.getMaxColour());
1693 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1695 // g.setFont(g.getFont().deriveFont(
1696 // AffineTransform.getScaleInstance(
1697 // width/g.getFontMetrics().stringWidth("Label"),
1698 // height/g.getFontMetrics().getHeight())));
1700 g.drawString(MessageManager.getString("label.label"), 0, 0);
1705 Color minCol = gcol.getMinColour();
1707 g.fillRect(0, 0, s1, height);
1710 g.setColor(Color.white);
1711 g.fillRect(s1, 0, e1 - s1, height);
1713 g.setColor(gcol.getMaxColour());
1714 g.fillRect(0, e1, width - e1, height);
1719 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1724 FeatureColourI currentColor;
1726 FeatureColourChooser chooser;
1732 JColorChooser colorChooser;
1736 protected static final String EDIT = "edit";
1738 int selectedRow = 0;
1740 public ColorEditor(FeatureSettings me)
1743 // Set up the editor (from the table's point of view),
1744 // which is a button.
1745 // This button brings up the color chooser dialog,
1746 // which is the editor from the user's point of view.
1747 button = new JButton();
1748 button.setActionCommand(EDIT);
1749 button.addActionListener(this);
1750 button.setBorderPainted(false);
1751 // Set up the dialog that the button brings up.
1752 colorChooser = new JColorChooser();
1753 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1754 colorChooser, this, // OK button handler
1755 null); // no CANCEL button handler
1759 * Handles events from the editor button and from the dialog's OK button.
1762 public void actionPerformed(ActionEvent e)
1765 if (EDIT.equals(e.getActionCommand()))
1767 // The user has clicked the cell, so
1768 // bring up the dialog.
1769 if (currentColor.isSimpleColour())
1771 // bring up simple color chooser
1772 button.setBackground(currentColor.getColour());
1773 colorChooser.setColor(currentColor.getColour());
1774 dialog.setVisible(true);
1778 // bring up graduated chooser.
1779 chooser = new FeatureColourChooser(me.fr, type);
1780 chooser.setRequestFocusEnabled(true);
1781 chooser.requestFocus();
1782 chooser.addActionListener(this);
1784 // Make the renderer reappear.
1785 fireEditingStopped();
1789 { // User pressed dialog's "OK" button.
1790 if (currentColor.isSimpleColour())
1792 currentColor = new FeatureColour(colorChooser.getColor());
1796 currentColor = chooser.getLastColour();
1798 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1799 fireEditingStopped();
1800 me.table.validate();
1804 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1806 public Object getCellEditorValue()
1808 return currentColor;
1811 // Implement the one method defined by TableCellEditor.
1813 public Component getTableCellEditorComponent(JTable table, Object value,
1814 boolean isSelected, int row, int column)
1816 currentColor = (FeatureColourI) value;
1817 this.selectedRow = row;
1818 type = me.table.getValueAt(row, 0).toString();
1819 button.setOpaque(true);
1820 button.setBackground(me.getBackground());
1821 if (!currentColor.isSimpleColour())
1823 JLabel btn = new JLabel();
1824 btn.setSize(button.getSize());
1825 FeatureSettings.renderGraduatedColor(btn, currentColor);
1826 button.setBackground(btn.getBackground());
1827 button.setIcon(btn.getIcon());
1828 button.setText(btn.getText());
1833 button.setIcon(null);
1834 button.setBackground(currentColor.getColour());