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;
43 import java.awt.Dimension;
45 import java.awt.Graphics;
46 import java.awt.GridLayout;
47 import java.awt.Rectangle;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
50 import java.awt.event.ItemEvent;
51 import java.awt.event.ItemListener;
52 import java.awt.event.MouseAdapter;
53 import java.awt.event.MouseEvent;
54 import java.awt.event.MouseMotionAdapter;
55 import java.beans.PropertyChangeEvent;
56 import java.beans.PropertyChangeListener;
58 import java.io.FileInputStream;
59 import java.io.FileOutputStream;
60 import java.io.InputStreamReader;
61 import java.io.OutputStreamWriter;
62 import java.io.PrintWriter;
63 import java.util.Arrays;
64 import java.util.HashSet;
65 import java.util.Hashtable;
66 import java.util.Iterator;
67 import java.util.List;
70 import java.util.Vector;
72 import javax.help.HelpSetException;
73 import javax.swing.AbstractCellEditor;
74 import javax.swing.BorderFactory;
75 import javax.swing.Icon;
76 import javax.swing.JButton;
77 import javax.swing.JCheckBox;
78 import javax.swing.JCheckBoxMenuItem;
79 import javax.swing.JColorChooser;
80 import javax.swing.JDialog;
81 import javax.swing.JInternalFrame;
82 import javax.swing.JLabel;
83 import javax.swing.JLayeredPane;
84 import javax.swing.JMenuItem;
85 import javax.swing.JPanel;
86 import javax.swing.JPopupMenu;
87 import javax.swing.JScrollPane;
88 import javax.swing.JSlider;
89 import javax.swing.JTabbedPane;
90 import javax.swing.JTable;
91 import javax.swing.ListSelectionModel;
92 import javax.swing.SwingConstants;
93 import javax.swing.SwingUtilities;
94 import javax.swing.event.ChangeEvent;
95 import javax.swing.event.ChangeListener;
96 import javax.swing.table.AbstractTableModel;
97 import javax.swing.table.TableCellEditor;
98 import javax.swing.table.TableCellRenderer;
100 public class FeatureSettings extends JPanel implements
101 FeatureSettingsControllerI
103 DasSourceBrowser dassourceBrowser;
105 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
107 JPanel settingsPane = new JPanel();
109 JPanel dasSettingsPane = new JPanel();
111 final FeatureRenderer fr;
113 public final AlignFrame af;
115 Object[][] originalData;
117 private float originalTransparency;
119 final JInternalFrame frame;
121 JScrollPane scrollPane = new JScrollPane();
127 JSlider transparency = new JSlider();
129 JPanel transPanel = new JPanel(new GridLayout(1, 2));
131 private static final int MIN_WIDTH = 400;
133 private static final int MIN_HEIGHT = 400;
140 public FeatureSettings(AlignFrame af)
143 fr = af.getFeatureRenderer();
144 // allow transparency to be recovered
145 transparency.setMaximum(100 - (int) ((originalTransparency = fr
146 .getTransparency()) * 100));
151 } catch (Exception ex)
153 ex.printStackTrace();
159 public String getToolTipText(MouseEvent e)
161 if (table.columnAtPoint(e.getPoint()) == 0)
164 * Tooltip for feature name only
166 return JvSwingUtils.wrapTooltip(true, MessageManager
167 .getString("label.feature_settings_click_drag"));
172 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
173 table.setFont(new Font("Verdana", Font.PLAIN, 12));
174 table.setDefaultRenderer(Color.class, new ColorRenderer());
176 table.setDefaultEditor(Color.class, new ColorEditor(this));
178 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
179 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
180 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
182 table.addMouseListener(new MouseAdapter()
185 public void mousePressed(MouseEvent evt)
187 selectedRow = table.rowAtPoint(evt.getPoint());
188 if (evt.isPopupTrigger())
190 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
191 table.getValueAt(selectedRow, 1), fr.getMinMax(),
192 evt.getX(), evt.getY());
194 else if (evt.getClickCount() == 2)
196 boolean invertSelection = evt.isAltDown();
197 boolean toggleSelection = Platform.isControlDown(evt);
198 boolean extendSelection = evt.isShiftDown();
199 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
200 invertSelection, extendSelection, toggleSelection,
201 (String) table.getValueAt(selectedRow, 0));
205 // isPopupTrigger fires on mouseReleased on Windows
207 public void mouseReleased(MouseEvent evt)
209 selectedRow = table.rowAtPoint(evt.getPoint());
210 if (evt.isPopupTrigger())
212 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
213 table.getValueAt(selectedRow, 1), fr.getMinMax(),
214 evt.getX(), evt.getY());
219 table.addMouseMotionListener(new MouseMotionAdapter()
222 public void mouseDragged(MouseEvent evt)
224 int newRow = table.rowAtPoint(evt.getPoint());
225 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
228 * reposition 'selectedRow' to 'newRow' (the dragged to location)
229 * this could be more than one row away for a very fast drag action
230 * so just swap it with adjacent rows until we get it there
232 Object[][] data = ((FeatureTableModel) table.getModel())
234 int direction = newRow < selectedRow ? -1 : 1;
235 for (int i = selectedRow; i != newRow; i += direction)
237 Object[] temp = data[i];
238 data[i] = data[i + direction];
239 data[i + direction] = temp;
241 updateFeatureRenderer(data);
243 selectedRow = newRow;
247 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
248 // MessageManager.getString("label.feature_settings_click_drag")));
249 scrollPane.setViewportView(table);
251 dassourceBrowser = new DasSourceBrowser(this);
252 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
254 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
256 fr.findAllFeatures(true); // display everything!
259 discoverAllFeatureData();
260 final PropertyChangeListener change;
261 final FeatureSettings fs = this;
262 fr.addPropertyChangeListener(change = new PropertyChangeListener()
265 public void propertyChange(PropertyChangeEvent evt)
267 if (!fs.resettingTable && !fs.handlingUpdate)
269 fs.handlingUpdate = true;
270 fs.resetTable(null); // new groups may be added with new seuqence
271 // feature types only
272 fs.handlingUpdate = false;
278 frame = new JInternalFrame();
279 frame.setContentPane(this);
280 if (Platform.isAMac())
282 Desktop.addInternalFrame(frame,
283 MessageManager.getString("label.sequence_feature_settings"),
288 Desktop.addInternalFrame(frame,
289 MessageManager.getString("label.sequence_feature_settings"),
292 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
294 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
297 public void internalFrameClosed(
298 javax.swing.event.InternalFrameEvent evt)
300 fr.removePropertyChangeListener(change);
301 dassourceBrowser.fs = null;
304 frame.setLayer(JLayeredPane.PALETTE_LAYER);
307 protected void popupSort(final int selectedRow, final String type,
308 final Object typeCol, final Map<String, float[][]> minmax, int x,
311 final FeatureColourI featureColour = (FeatureColourI) typeCol;
313 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
314 "label.settings_for_param", new String[] { type }));
315 JMenuItem scr = new JMenuItem(
316 MessageManager.getString("label.sort_by_score"));
318 final FeatureSettings me = this;
319 scr.addActionListener(new ActionListener()
323 public void actionPerformed(ActionEvent e)
325 me.af.avc.sortAlignmentByFeatureScore(Arrays
326 .asList(new String[] { type }));
330 JMenuItem dens = new JMenuItem(
331 MessageManager.getString("label.sort_by_density"));
332 dens.addActionListener(new ActionListener()
336 public void actionPerformed(ActionEvent e)
338 me.af.avc.sortAlignmentByFeatureDensity(Arrays
339 .asList(new String[] { type }));
346 final float[][] typeMinMax = minmax.get(type);
348 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
349 * this is broken at the moment and isn't that useful anyway!
350 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
353 * public void actionPerformed(ActionEvent e) {
354 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
355 * null); } else { minmax.put(type, typeMinMax); } }
361 if (typeMinMax != null && typeMinMax[0] != null)
363 // if (table.getValueAt(row, column));
364 // graduated colourschemes for those where minmax exists for the
365 // positional features
366 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
368 mxcol.setSelected(!featureColour.isSimpleColour());
370 mxcol.addActionListener(new ActionListener()
372 JColorChooser colorChooser;
375 public void actionPerformed(ActionEvent e)
377 if (e.getSource() == mxcol)
379 if (featureColour.isSimpleColour())
381 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
383 fc.addActionListener(this);
387 // bring up simple color chooser
388 colorChooser = new JColorChooser();
389 JDialog dialog = JColorChooser.createDialog(me,
390 "Select new Colour", true, // modal
391 colorChooser, this, // OK button handler
392 null); // no CANCEL button handler
393 colorChooser.setColor(featureColour.getMaxColour());
394 dialog.setVisible(true);
399 if (e.getSource() instanceof FeatureColourChooser)
401 FeatureColourChooser fc = (FeatureColourChooser) e
403 table.setValueAt(fc.getLastColour(), selectedRow, 1);
408 // probably the color chooser!
410 new FeatureColour(colorChooser.getColor()),
413 me.updateFeatureRenderer(
414 ((FeatureTableModel) table.getModel()).getData(),
423 JMenuItem selCols = new JMenuItem(
424 MessageManager.getString("label.select_columns_containing"));
425 selCols.addActionListener(new ActionListener()
428 public void actionPerformed(ActionEvent arg0)
430 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
434 JMenuItem clearCols = new JMenuItem(
435 MessageManager.getString("label.select_columns_not_containing"));
436 clearCols.addActionListener(new ActionListener()
439 public void actionPerformed(ActionEvent arg0)
441 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
445 JMenuItem hideCols = new JMenuItem(
446 MessageManager.getString("label.hide_columns_containing"));
447 hideCols.addActionListener(new ActionListener()
450 public void actionPerformed(ActionEvent arg0)
452 fr.ap.alignFrame.hideFeatureColumns(type, true);
455 JMenuItem hideOtherCols = new JMenuItem(
456 MessageManager.getString("label.hide_columns_not_containing"));
457 hideOtherCols.addActionListener(new ActionListener()
460 public void actionPerformed(ActionEvent arg0)
462 fr.ap.alignFrame.hideFeatureColumns(type, false);
468 men.add(hideOtherCols);
469 men.show(table, x, y);
473 * true when Feature Settings are updating from feature renderer
475 private boolean handlingUpdate = false;
478 * contains a float[3] for each feature type string. created by setTableData
480 Map<String, float[]> typeWidth = null;
483 synchronized public void discoverAllFeatureData()
485 Vector<String> allFeatures = new Vector<String>();
486 Vector<String> allGroups = new Vector<String>();
487 SequenceFeature[] tmpfeatures;
489 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
491 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
492 .getSequenceFeatures();
493 if (tmpfeatures == null)
499 while (index < tmpfeatures.length)
501 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
507 if (tmpfeatures[index].getFeatureGroup() != null)
509 group = tmpfeatures[index].featureGroup;
510 if (!allGroups.contains(group))
512 allGroups.addElement(group);
513 checkGroupState(group);
517 if (!allFeatures.contains(tmpfeatures[index].getType()))
519 allFeatures.addElement(tmpfeatures[index].getType());
531 * Synchronise gui group list and check visibility of group
534 * @return true if group is visible
536 private boolean checkGroupState(String group)
538 boolean visible = fr.checkGroupVisibility(group, true);
540 for (int g = 0; g < groupPanel.getComponentCount(); g++)
542 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
544 ((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>();
587 Set<String> foundGroups = new HashSet<String>();
589 // Find out which features should be visible depending on which groups
590 // are selected / deselected
591 // and recompute average width ordering
592 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
595 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
596 .getSequenceFeatures();
597 if (tmpfeatures == null)
603 while (index < tmpfeatures.length)
605 group = tmpfeatures[index].featureGroup;
606 foundGroups.add(group);
608 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
614 if (group == null || checkGroupState(group))
616 type = tmpfeatures[index].getType();
617 if (!visibleChecks.contains(type))
619 visibleChecks.addElement(type);
622 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
624 typeWidth.put(tmpfeatures[index].getType(),
625 avWidth = new float[3]);
629 avWidth = typeWidth.get(tmpfeatures[index].getType());
632 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
634 avWidth[1] += 1 + tmpfeatures[index].getBegin()
635 - tmpfeatures[index].getEnd();
639 avWidth[1] += 1 + tmpfeatures[index].getEnd()
640 - tmpfeatures[index].getBegin();
646 int fSize = visibleChecks.size();
647 Object[][] data = new Object[fSize][3];
650 if (fr.hasRenderOrder())
654 fr.findAllFeatures(groupChanged != null); // prod to update
655 // colourschemes. but don't
657 // First add the checks in the previous render order,
658 // in case the window has been closed and reopened
660 List<String> frl = fr.getRenderOrder();
661 for (int ro = frl.size() - 1; ro > -1; ro--)
665 if (!visibleChecks.contains(type))
670 data[dataIndex][0] = type;
671 data[dataIndex][1] = fr.getFeatureStyle(type);
672 data[dataIndex][2] = new Boolean(af.getViewport()
673 .getFeaturesDisplayed().isVisible(type));
675 visibleChecks.removeElement(type);
679 fSize = visibleChecks.size();
680 for (int i = 0; i < fSize; i++)
682 // These must be extra features belonging to the group
683 // which was just selected
684 type = visibleChecks.elementAt(i).toString();
685 data[dataIndex][0] = type;
687 data[dataIndex][1] = fr.getFeatureStyle(type);
688 if (data[dataIndex][1] == null)
690 // "Colour has been updated in another view!!"
691 fr.clearRenderOrder();
695 data[dataIndex][2] = new Boolean(true);
699 if (originalData == null)
701 originalData = new Object[data.length][3];
702 for (int i = 0; i < data.length; i++)
704 System.arraycopy(data[i], 0, originalData[i], 0, 3);
708 table.setModel(new FeatureTableModel(data));
709 table.getColumnModel().getColumn(0).setPreferredWidth(200);
711 groupPanel.setLayout(new GridLayout(fr.getFeatureGroupsSize() / 4 + 1,
713 pruneGroups(foundGroups);
714 groupPanel.validate();
716 updateFeatureRenderer(data, groupChanged != null);
717 resettingTable = false;
721 * Remove from the groups panel any checkboxes for groups that are not in the
722 * foundGroups set. This enables removing a group from the display when the
723 * last feature in that group is deleted.
727 protected void pruneGroups(Set<String> foundGroups)
729 for (int g = 0; g < groupPanel.getComponentCount(); g++)
731 JCheckBox checkbox = (JCheckBox) groupPanel.getComponent(g);
732 if (!foundGroups.contains(checkbox.getText()))
734 groupPanel.remove(checkbox);
740 * reorder data based on the featureRenderers global priority list.
744 private void ensureOrder(Object[][] data)
746 boolean sort = false;
747 float[] order = new float[data.length];
748 for (int i = 0; i < order.length; i++)
750 order[i] = fr.getOrder(data[i][0].toString());
753 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
757 sort = sort || order[i - 1] > order[i];
762 jalview.util.QuickSort.sort(order, data);
768 JalviewFileChooser chooser = new JalviewFileChooser("fc",
769 "Sequence Feature Colours");
770 chooser.setFileView(new JalviewFileView());
771 chooser.setDialogTitle(MessageManager
772 .getString("label.load_feature_colours"));
773 chooser.setToolTipText(MessageManager.getString("action.load"));
775 int value = chooser.showOpenDialog(this);
777 if (value == JalviewFileChooser.APPROVE_OPTION)
779 File file = chooser.getSelectedFile();
783 InputStreamReader in = new InputStreamReader(new FileInputStream(
786 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
788 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
791 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
794 Color mincol = null, maxcol = null;
797 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
798 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
800 } catch (Exception e)
802 Cache.log.warn("Couldn't parse out graduated feature color.",
805 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
806 newcol.getMin(), newcol.getMax());
807 if (newcol.hasAutoScale())
809 gcol.setAutoScaled(newcol.getAutoScale());
811 if (newcol.hasColourByLabel())
813 gcol.setColourByLabel(newcol.getColourByLabel());
815 if (newcol.hasThreshold())
817 gcol.setThreshold(newcol.getThreshold());
819 if (newcol.getThreshType().length() > 0)
821 String ttyp = newcol.getThreshType();
822 if (ttyp.equalsIgnoreCase("ABOVE"))
824 gcol.setAboveThreshold(true);
826 if (ttyp.equalsIgnoreCase("BELOW"))
828 gcol.setBelowThreshold(true);
831 fr.setColour(name = newcol.getName(), gcol);
835 Color color = new Color(
836 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
837 fr.setColour(name = jucs.getColour(i).getName(),
838 new FeatureColour(color));
840 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
845 Object[][] data = ((FeatureTableModel) table.getModel())
848 updateFeatureRenderer(data, false);
851 } catch (Exception ex)
853 System.out.println("Error loading User Colour File\n" + ex);
860 JalviewFileChooser chooser = new JalviewFileChooser("fc",
861 "Sequence Feature Colours");
862 chooser.setFileView(new JalviewFileView());
863 chooser.setDialogTitle(MessageManager
864 .getString("label.save_feature_colours"));
865 chooser.setToolTipText(MessageManager.getString("action.save"));
867 int value = chooser.showSaveDialog(this);
869 if (value == JalviewFileChooser.APPROVE_OPTION)
871 String choice = chooser.getSelectedFile().getPath();
872 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
873 ucs.setSchemeName("Sequence Features");
876 PrintWriter out = new PrintWriter(new OutputStreamWriter(
877 new FileOutputStream(choice), "UTF-8"));
879 Set<String> fr_colours = fr.getAllFeatureColours();
880 Iterator<String> e = fr_colours.iterator();
881 float[] sortOrder = new float[fr_colours.size()];
882 String[] sortTypes = new String[fr_colours.size()];
886 sortTypes[i] = e.next();
887 sortOrder[i] = fr.getOrder(sortTypes[i]);
890 QuickSort.sort(sortOrder, sortTypes);
892 for (i = 0; i < sortTypes.length; i++)
894 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
895 col.setName(sortTypes[i]);
896 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
897 if (fcol.isSimpleColour())
899 col.setRGB(Format.getHexString(fcol.getColour()));
903 col.setRGB(Format.getHexString(fcol.getMaxColour()));
904 col.setMin(fcol.getMin());
905 col.setMax(fcol.getMax());
906 col.setMinRGB(jalview.util.Format.getHexString(fcol
908 col.setAutoScale(fcol.isAutoScaled());
909 col.setThreshold(fcol.getThreshold());
910 col.setColourByLabel(fcol.isColourByLabel());
911 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
912 .isBelowThreshold() ? "BELOW" : "NONE"));
918 } catch (Exception ex)
920 ex.printStackTrace();
925 public void invertSelection()
927 for (int i = 0; i < table.getRowCount(); i++)
929 Boolean value = (Boolean) table.getValueAt(i, 2);
931 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
935 public void orderByAvWidth()
937 if (table == null || table.getModel() == null)
941 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
942 float[] width = new float[data.length];
946 for (int i = 0; i < data.length; i++)
948 awidth = typeWidth.get(data[i][0]);
951 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
952 // weight - but have to make per
953 // sequence, too (awidth[2])
954 // if (width[i]==1) // hack to distinguish single width sequences.
966 boolean sort = false;
967 for (int i = 0; i < width.length; i++)
969 // awidth = (float[]) typeWidth.get(data[i][0]);
972 width[i] = fr.getOrder(data[i][0].toString());
975 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
980 width[i] /= max; // normalize
981 fr.setOrder(data[i][0].toString(), width[i]); // store for later
985 sort = sort || width[i - 1] > width[i];
990 jalview.util.QuickSort.sort(width, data);
991 // update global priority order
994 updateFeatureRenderer(data, false);
1002 frame.setClosed(true);
1003 } catch (Exception exe)
1009 public void updateFeatureRenderer(Object[][] data)
1011 updateFeatureRenderer(data, true);
1015 * Update the priority order of features; only repaint if this changed the
1016 * order of visible features
1021 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1023 if (fr.setFeaturePriority(data, visibleNew))
1025 af.alignPanel.paintAlignment(true);
1029 int selectedRow = -1;
1031 JTabbedPane tabbedPane = new JTabbedPane();
1033 BorderLayout borderLayout1 = new BorderLayout();
1035 BorderLayout borderLayout2 = new BorderLayout();
1037 BorderLayout borderLayout3 = new BorderLayout();
1039 JPanel bigPanel = new JPanel();
1041 BorderLayout borderLayout4 = new BorderLayout();
1043 JButton invert = new JButton();
1045 JPanel buttonPanel = new JPanel();
1047 JButton cancel = new JButton();
1049 JButton ok = new JButton();
1051 JButton loadColours = new JButton();
1053 JButton saveColours = new JButton();
1055 JPanel dasButtonPanel = new JPanel();
1057 JButton fetchDAS = new JButton();
1059 JButton saveDAS = new JButton();
1061 JButton cancelDAS = new JButton();
1063 JButton optimizeOrder = new JButton();
1065 JButton sortByScore = new JButton();
1067 JButton sortByDens = new JButton();
1069 JButton help = new JButton();
1071 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1073 private void jbInit() throws Exception
1075 this.setLayout(borderLayout1);
1076 settingsPane.setLayout(borderLayout2);
1077 dasSettingsPane.setLayout(borderLayout3);
1078 bigPanel.setLayout(borderLayout4);
1080 groupPanel = new JPanel();
1081 bigPanel.add(groupPanel, BorderLayout.NORTH);
1083 invert.setFont(JvSwingUtils.getLabelFont());
1084 invert.setText(MessageManager.getString("label.invert_selection"));
1085 invert.addActionListener(new ActionListener()
1088 public void actionPerformed(ActionEvent e)
1093 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1094 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1095 optimizeOrder.addActionListener(new ActionListener()
1098 public void actionPerformed(ActionEvent e)
1103 sortByScore.setFont(JvSwingUtils.getLabelFont());
1105 .setText(MessageManager.getString("label.seq_sort_by_score"));
1106 sortByScore.addActionListener(new ActionListener()
1109 public void actionPerformed(ActionEvent e)
1111 af.avc.sortAlignmentByFeatureScore(null);
1114 sortByDens.setFont(JvSwingUtils.getLabelFont());
1115 sortByDens.setText(MessageManager
1116 .getString("label.sequence_sort_by_density"));
1117 sortByDens.addActionListener(new ActionListener()
1120 public void actionPerformed(ActionEvent e)
1122 af.avc.sortAlignmentByFeatureDensity(null);
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 help.setFont(JvSwingUtils.getLabelFont());
1142 help.setText(MessageManager.getString("action.help"));
1143 help.addActionListener(new ActionListener()
1146 public void actionPerformed(ActionEvent e)
1150 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1151 } catch (HelpSetException e1)
1153 e1.printStackTrace();
1157 cancel.setFont(JvSwingUtils.getLabelFont());
1158 cancel.setText(MessageManager.getString("action.cancel"));
1159 cancel.addActionListener(new ActionListener()
1162 public void actionPerformed(ActionEvent e)
1164 fr.setTransparency(originalTransparency);
1165 updateFeatureRenderer(originalData);
1169 ok.setFont(JvSwingUtils.getLabelFont());
1170 ok.setText(MessageManager.getString("action.ok"));
1171 ok.addActionListener(new ActionListener()
1174 public void actionPerformed(ActionEvent e)
1179 loadColours.setFont(JvSwingUtils.getLabelFont());
1180 loadColours.setText(MessageManager.getString("label.load_colours"));
1181 loadColours.addActionListener(new ActionListener()
1184 public void actionPerformed(ActionEvent e)
1189 saveColours.setFont(JvSwingUtils.getLabelFont());
1190 saveColours.setText(MessageManager.getString("label.save_colours"));
1191 saveColours.addActionListener(new ActionListener()
1194 public void actionPerformed(ActionEvent e)
1199 transparency.addChangeListener(new ChangeListener()
1202 public void stateChanged(ChangeEvent evt)
1204 fr.setTransparency((100 - transparency.getValue()) / 100f);
1205 af.alignPanel.paintAlignment(true);
1209 transparency.setMaximum(70);
1210 transparency.setToolTipText(MessageManager
1211 .getString("label.transparency_tip"));
1212 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1213 fetchDAS.addActionListener(new ActionListener()
1216 public void actionPerformed(ActionEvent e)
1218 fetchDAS_actionPerformed(e);
1221 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1222 saveDAS.addActionListener(new ActionListener()
1225 public void actionPerformed(ActionEvent e)
1227 saveDAS_actionPerformed(e);
1230 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1231 dasSettingsPane.setBorder(null);
1232 cancelDAS.setEnabled(false);
1233 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1234 cancelDAS.addActionListener(new ActionListener()
1237 public void actionPerformed(ActionEvent e)
1239 cancelDAS_actionPerformed(e);
1242 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1243 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1245 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1247 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1248 transbuttons.add(optimizeOrder);
1249 transbuttons.add(invert);
1250 transbuttons.add(sortByScore);
1251 transbuttons.add(sortByDens);
1252 transbuttons.add(help);
1253 JPanel sliderPanel = new JPanel();
1254 sliderPanel.add(transparency);
1255 transPanel.add(transparency);
1256 transPanel.add(transbuttons);
1257 buttonPanel.add(ok);
1258 buttonPanel.add(cancel);
1259 buttonPanel.add(loadColours);
1260 buttonPanel.add(saveColours);
1261 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1262 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1263 dasButtonPanel.add(fetchDAS);
1264 dasButtonPanel.add(cancelDAS);
1265 dasButtonPanel.add(saveDAS);
1266 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1267 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1270 public void fetchDAS_actionPerformed(ActionEvent e)
1272 fetchDAS.setEnabled(false);
1273 cancelDAS.setEnabled(true);
1274 dassourceBrowser.setGuiEnabled(false);
1275 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1276 .getSelectedSources();
1277 doDasFeatureFetch(selectedSources, true, true);
1281 * get the features from selectedSources for all or the current selection
1283 * @param selectedSources
1284 * @param checkDbRefs
1285 * @param promptFetchDbRefs
1287 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1288 boolean checkDbRefs, boolean promptFetchDbRefs)
1290 SequenceI[] dataset, seqs;
1292 AlignmentViewport vp = af.getViewport();
1293 if (vp.getSelectionGroup() != null
1294 && vp.getSelectionGroup().getSize() > 0)
1296 iSize = vp.getSelectionGroup().getSize();
1297 dataset = new SequenceI[iSize];
1298 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1302 iSize = vp.getAlignment().getHeight();
1303 seqs = vp.getAlignment().getSequencesArray();
1306 dataset = new SequenceI[iSize];
1307 for (int i = 0; i < iSize; i++)
1309 dataset[i] = seqs[i].getDatasetSequence();
1312 cancelDAS.setEnabled(true);
1313 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1314 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1315 af.getViewport().setShowSequenceFeatures(true);
1316 af.showSeqFeatures.setSelected(true);
1320 * blocking call to initialise the das source browser
1322 public void initDasSources()
1324 dassourceBrowser.initDasSources();
1328 * examine the current list of das sources and return any matching the given
1329 * nicknames in sources
1332 * Vector of Strings to resolve to DAS source nicknames.
1333 * @return sources that are present in source list.
1335 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1337 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1341 * get currently selected das sources. ensure you have called initDasSources
1342 * before calling this.
1344 * @return vector of selected das source nicknames
1346 public Vector<jalviewSourceI> getSelectedSources()
1348 return dassourceBrowser.getSelectedSources();
1352 * properly initialise DAS fetcher and then initiate a new thread to fetch
1353 * features from the named sources (rather than any turned on by default)
1357 * if true then runs in same thread, otherwise passes to the Swing
1360 public void fetchDasFeatures(Vector<String> sources, boolean block)
1363 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1364 .resolveSourceNicknames(sources);
1365 if (resolved.size() == 0)
1367 resolved = dassourceBrowser.getSelectedSources();
1369 if (resolved.size() > 0)
1371 final List<jalviewSourceI> dassources = resolved;
1372 fetchDAS.setEnabled(false);
1373 // cancelDAS.setEnabled(true); doDasFetch does this.
1374 Runnable fetcher = new Runnable()
1380 doDasFeatureFetch(dassources, true, false);
1390 SwingUtilities.invokeLater(fetcher);
1395 public void saveDAS_actionPerformed(ActionEvent e)
1398 .saveProperties(jalview.bin.Cache.applicationProperties);
1401 public void complete()
1403 fetchDAS.setEnabled(true);
1404 cancelDAS.setEnabled(false);
1405 dassourceBrowser.setGuiEnabled(true);
1409 public void cancelDAS_actionPerformed(ActionEvent e)
1411 if (dasFeatureFetcher != null)
1413 dasFeatureFetcher.cancel();
1418 public void noDasSourceActive()
1422 .showInternalConfirmDialog(
1425 .getString("label.no_das_sources_selected_warn"),
1427 .getString("label.no_das_sources_selected_title"),
1428 JvOptionPane.DEFAULT_OPTION,
1429 JvOptionPane.INFORMATION_MESSAGE);
1432 // ///////////////////////////////////////////////////////////////////////
1433 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1434 // ///////////////////////////////////////////////////////////////////////
1435 class FeatureTableModel extends AbstractTableModel
1437 FeatureTableModel(Object[][] data)
1442 private String[] columnNames = {
1443 MessageManager.getString("label.feature_type"),
1444 MessageManager.getString("action.colour"),
1445 MessageManager.getString("label.display") };
1447 private Object[][] data;
1449 public Object[][] getData()
1454 public void setData(Object[][] data)
1460 public int getColumnCount()
1462 return columnNames.length;
1465 public Object[] getRow(int row)
1471 public int getRowCount()
1477 public String getColumnName(int col)
1479 return columnNames[col];
1483 public Object getValueAt(int row, int col)
1485 return data[row][col];
1489 public Class getColumnClass(int c)
1491 return getValueAt(0, c).getClass();
1495 public boolean isCellEditable(int row, int col)
1497 return col == 0 ? false : true;
1501 public void setValueAt(Object value, int row, int col)
1503 data[row][col] = value;
1504 fireTableCellUpdated(row, col);
1505 updateFeatureRenderer(data);
1510 class ColorRenderer extends JLabel implements TableCellRenderer
1512 javax.swing.border.Border unselectedBorder = null;
1514 javax.swing.border.Border selectedBorder = null;
1516 final String baseTT = "Click to edit, right/apple click for menu.";
1518 public ColorRenderer()
1520 setOpaque(true); // MUST do this for background to show up.
1521 setHorizontalTextPosition(SwingConstants.CENTER);
1522 setVerticalTextPosition(SwingConstants.CENTER);
1526 public Component getTableCellRendererComponent(JTable tbl,
1527 Object color, boolean isSelected, boolean hasFocus, int row,
1530 FeatureColourI cellColour = (FeatureColourI) color;
1531 // JLabel comp = new JLabel();
1535 // setBounds(getBounds());
1537 setToolTipText(baseTT);
1538 setBackground(tbl.getBackground());
1539 if (!cellColour.isSimpleColour())
1541 Rectangle cr = tbl.getCellRect(row, column, false);
1542 FeatureSettings.renderGraduatedColor(this, cellColour,
1543 (int) cr.getWidth(), (int) cr.getHeight());
1550 newColor = cellColour.getColour();
1551 setBackground(newColor);
1555 if (selectedBorder == null)
1557 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1558 tbl.getSelectionBackground());
1560 setBorder(selectedBorder);
1564 if (unselectedBorder == null)
1566 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1567 tbl.getBackground());
1569 setBorder(unselectedBorder);
1577 * update comp using rendering settings from gcol
1582 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1584 int w = comp.getWidth(), h = comp.getHeight();
1587 w = (int) comp.getPreferredSize().getWidth();
1588 h = (int) comp.getPreferredSize().getHeight();
1595 renderGraduatedColor(comp, gcol, w, h);
1598 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1601 boolean thr = false;
1604 if (gcol.isAboveThreshold())
1608 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1610 if (gcol.isBelowThreshold())
1614 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1616 if (gcol.isColourByLabel())
1618 tt = "Coloured by label text. " + tt;
1628 Color newColor = gcol.getMaxColour();
1629 comp.setBackground(newColor);
1630 // System.err.println("Width is " + w / 2);
1631 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1632 comp.setIcon(ficon);
1633 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1634 // + newColor.getGreen() + ", " + newColor.getBlue()
1635 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1636 // + ", " + minCol.getBlue() + ")");
1638 comp.setHorizontalAlignment(SwingConstants.CENTER);
1640 if (tt.length() > 0)
1642 if (comp.getToolTipText() == null)
1644 comp.setToolTipText(tt);
1648 comp.setToolTipText(tt + " " + comp.getToolTipText());
1654 class FeatureIcon implements Icon
1656 FeatureColourI gcol;
1660 boolean midspace = false;
1662 int width = 50, height = 20;
1664 int s1, e1; // start and end of midpoint band for thresholded symbol
1666 Color mpcolour = Color.white;
1668 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1688 public int getIconWidth()
1694 public int getIconHeight()
1700 public void paintIcon(Component c, Graphics g, int x, int y)
1703 if (gcol.isColourByLabel())
1706 g.fillRect(0, 0, width, height);
1707 // need an icon here.
1708 g.setColor(gcol.getMaxColour());
1710 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1712 // g.setFont(g.getFont().deriveFont(
1713 // AffineTransform.getScaleInstance(
1714 // width/g.getFontMetrics().stringWidth("Label"),
1715 // height/g.getFontMetrics().getHeight())));
1717 g.drawString(MessageManager.getString("label.label"), 0, 0);
1722 Color minCol = gcol.getMinColour();
1724 g.fillRect(0, 0, s1, height);
1727 g.setColor(Color.white);
1728 g.fillRect(s1, 0, e1 - s1, height);
1730 g.setColor(gcol.getMaxColour());
1731 g.fillRect(0, e1, width - e1, height);
1736 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1741 FeatureColourI currentColor;
1743 FeatureColourChooser chooser;
1749 JColorChooser colorChooser;
1753 protected static final String EDIT = "edit";
1755 int selectedRow = 0;
1757 public ColorEditor(FeatureSettings me)
1760 // Set up the editor (from the table's point of view),
1761 // which is a button.
1762 // This button brings up the color chooser dialog,
1763 // which is the editor from the user's point of view.
1764 button = new JButton();
1765 button.setActionCommand(EDIT);
1766 button.addActionListener(this);
1767 button.setBorderPainted(false);
1768 // Set up the dialog that the button brings up.
1769 colorChooser = new JColorChooser();
1770 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1771 colorChooser, this, // OK button handler
1772 null); // no CANCEL button handler
1776 * Handles events from the editor button and from the dialog's OK button.
1779 public void actionPerformed(ActionEvent e)
1782 if (EDIT.equals(e.getActionCommand()))
1784 // The user has clicked the cell, so
1785 // bring up the dialog.
1786 if (currentColor.isSimpleColour())
1788 // bring up simple color chooser
1789 button.setBackground(currentColor.getColour());
1790 colorChooser.setColor(currentColor.getColour());
1791 dialog.setVisible(true);
1795 // bring up graduated chooser.
1796 chooser = new FeatureColourChooser(me.fr, type);
1797 chooser.setRequestFocusEnabled(true);
1798 chooser.requestFocus();
1799 chooser.addActionListener(this);
1801 // Make the renderer reappear.
1802 fireEditingStopped();
1806 { // User pressed dialog's "OK" button.
1807 if (currentColor.isSimpleColour())
1809 currentColor = new FeatureColour(colorChooser.getColor());
1813 currentColor = chooser.getLastColour();
1815 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1816 fireEditingStopped();
1817 me.table.validate();
1821 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1823 public Object getCellEditorValue()
1825 return currentColor;
1828 // Implement the one method defined by TableCellEditor.
1830 public Component getTableCellEditorComponent(JTable table, Object value,
1831 boolean isSelected, int row, int column)
1833 currentColor = (FeatureColourI) value;
1834 this.selectedRow = row;
1835 type = me.table.getValueAt(row, 0).toString();
1836 button.setOpaque(true);
1837 button.setBackground(me.getBackground());
1838 if (!currentColor.isSimpleColour())
1840 JLabel btn = new JLabel();
1841 btn.setSize(button.getSize());
1842 FeatureSettings.renderGraduatedColor(btn, currentColor);
1843 button.setBackground(btn.getBackground());
1844 button.setIcon(btn.getIcon());
1845 button.setText(btn.getText());
1850 button.setIcon(null);
1851 button.setBackground(currentColor.getColour());