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 (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(
752 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
753 new String[] { "fc" },
754 new String[] { "Sequence Feature Colours" },
755 "Sequence Feature Colours");
756 chooser.setFileView(new jalview.io.JalviewFileView());
757 chooser.setDialogTitle(MessageManager
758 .getString("label.load_feature_colours"));
759 chooser.setToolTipText(MessageManager.getString("action.load"));
761 int value = chooser.showOpenDialog(this);
763 if (value == JalviewFileChooser.APPROVE_OPTION)
765 File file = chooser.getSelectedFile();
769 InputStreamReader in = new InputStreamReader(new FileInputStream(
772 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
774 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
777 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
780 Color mincol = null, maxcol = null;
783 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
784 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
786 } catch (Exception e)
788 Cache.log.warn("Couldn't parse out graduated feature color.",
791 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
792 newcol.getMin(), newcol.getMax());
793 if (newcol.hasAutoScale())
795 gcol.setAutoScaled(newcol.getAutoScale());
797 if (newcol.hasColourByLabel())
799 gcol.setColourByLabel(newcol.getColourByLabel());
801 if (newcol.hasThreshold())
803 gcol.setThreshold(newcol.getThreshold());
805 if (newcol.getThreshType().length() > 0)
807 String ttyp = newcol.getThreshType();
808 if (ttyp.equalsIgnoreCase("ABOVE"))
810 gcol.setAboveThreshold(true);
812 if (ttyp.equalsIgnoreCase("BELOW"))
814 gcol.setBelowThreshold(true);
817 fr.setColour(name = newcol.getName(), gcol);
821 Color color = new Color(
822 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
823 fr.setColour(name = jucs.getColour(i).getName(),
824 new FeatureColour(color));
826 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
831 Object[][] data = ((FeatureTableModel) table.getModel())
834 updateFeatureRenderer(data, false);
837 } catch (Exception ex)
839 System.out.println("Error loading User Colour File\n" + ex);
846 JalviewFileChooser chooser = new JalviewFileChooser(
847 Cache.getProperty("LAST_DIRECTORY"),
848 new String[] { "fc" },
849 new String[] { "Sequence Feature Colours" },
850 "Sequence Feature Colours");
851 chooser.setFileView(new jalview.io.JalviewFileView());
852 chooser.setDialogTitle(MessageManager
853 .getString("label.save_feature_colours"));
854 chooser.setToolTipText(MessageManager.getString("action.save"));
856 int value = chooser.showSaveDialog(this);
858 if (value == JalviewFileChooser.APPROVE_OPTION)
860 String choice = chooser.getSelectedFile().getPath();
861 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
862 ucs.setSchemeName("Sequence Features");
865 PrintWriter out = new PrintWriter(new OutputStreamWriter(
866 new FileOutputStream(choice), "UTF-8"));
868 Set<String> fr_colours = fr.getAllFeatureColours();
869 Iterator<String> e = fr_colours.iterator();
870 float[] sortOrder = new float[fr_colours.size()];
871 String[] sortTypes = new String[fr_colours.size()];
875 sortTypes[i] = e.next();
876 sortOrder[i] = fr.getOrder(sortTypes[i]);
879 QuickSort.sort(sortOrder, sortTypes);
881 for (i = 0; i < sortTypes.length; i++)
883 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
884 col.setName(sortTypes[i]);
885 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
886 if (fcol.isSimpleColour())
888 col.setRGB(Format.getHexString(fcol.getColour()));
892 col.setRGB(Format.getHexString(fcol.getMaxColour()));
893 col.setMin(fcol.getMin());
894 col.setMax(fcol.getMax());
895 col.setMinRGB(jalview.util.Format.getHexString(fcol
897 col.setAutoScale(fcol.isAutoScaled());
898 col.setThreshold(fcol.getThreshold());
899 col.setColourByLabel(fcol.isColourByLabel());
900 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
901 .isBelowThreshold() ? "BELOW" : "NONE"));
907 } catch (Exception ex)
909 ex.printStackTrace();
914 public void invertSelection()
916 for (int i = 0; i < table.getRowCount(); i++)
918 Boolean value = (Boolean) table.getValueAt(i, 2);
920 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
924 public void orderByAvWidth()
926 if (table == null || table.getModel() == null)
930 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
931 float[] width = new float[data.length];
935 for (int i = 0; i < data.length; i++)
937 awidth = typeWidth.get(data[i][0]);
940 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
941 // weight - but have to make per
942 // sequence, too (awidth[2])
943 // if (width[i]==1) // hack to distinguish single width sequences.
955 boolean sort = false;
956 for (int i = 0; i < width.length; i++)
958 // awidth = (float[]) typeWidth.get(data[i][0]);
961 width[i] = fr.getOrder(data[i][0].toString());
964 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
969 width[i] /= max; // normalize
970 fr.setOrder(data[i][0].toString(), width[i]); // store for later
974 sort = sort || width[i - 1] > width[i];
979 jalview.util.QuickSort.sort(width, data);
980 // update global priority order
983 updateFeatureRenderer(data, false);
991 frame.setClosed(true);
992 } catch (Exception exe)
998 public void updateFeatureRenderer(Object[][] data)
1000 updateFeatureRenderer(data, true);
1004 * Update the priority order of features; only repaint if this changed the
1005 * order of visible features
1010 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1012 if (fr.setFeaturePriority(data, visibleNew))
1014 af.alignPanel.paintAlignment(true);
1018 int selectedRow = -1;
1020 JTabbedPane tabbedPane = new JTabbedPane();
1022 BorderLayout borderLayout1 = new BorderLayout();
1024 BorderLayout borderLayout2 = new BorderLayout();
1026 BorderLayout borderLayout3 = new BorderLayout();
1028 JPanel bigPanel = new JPanel();
1030 BorderLayout borderLayout4 = new BorderLayout();
1032 JButton invert = new JButton();
1034 JPanel buttonPanel = new JPanel();
1036 JButton cancel = new JButton();
1038 JButton ok = new JButton();
1040 JButton loadColours = new JButton();
1042 JButton saveColours = new JButton();
1044 JPanel dasButtonPanel = new JPanel();
1046 JButton fetchDAS = new JButton();
1048 JButton saveDAS = new JButton();
1050 JButton cancelDAS = new JButton();
1052 JButton optimizeOrder = new JButton();
1054 JButton sortByScore = new JButton();
1056 JButton sortByDens = new JButton();
1058 JButton help = new JButton();
1060 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1062 private void jbInit() throws Exception
1064 this.setLayout(borderLayout1);
1065 settingsPane.setLayout(borderLayout2);
1066 dasSettingsPane.setLayout(borderLayout3);
1067 bigPanel.setLayout(borderLayout4);
1068 invert.setFont(JvSwingUtils.getLabelFont());
1069 invert.setText(MessageManager.getString("label.invert_selection"));
1070 invert.addActionListener(new ActionListener()
1073 public void actionPerformed(ActionEvent e)
1078 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1079 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1080 optimizeOrder.addActionListener(new ActionListener()
1083 public void actionPerformed(ActionEvent e)
1088 sortByScore.setFont(JvSwingUtils.getLabelFont());
1090 .setText(MessageManager.getString("label.seq_sort_by_score"));
1091 sortByScore.addActionListener(new ActionListener()
1094 public void actionPerformed(ActionEvent e)
1096 af.avc.sortAlignmentByFeatureScore(null);
1099 sortByDens.setFont(JvSwingUtils.getLabelFont());
1100 sortByDens.setText(MessageManager
1101 .getString("label.sequence_sort_by_density"));
1102 sortByDens.addActionListener(new ActionListener()
1105 public void actionPerformed(ActionEvent e)
1107 af.avc.sortAlignmentByFeatureDensity(null);
1110 help.setFont(JvSwingUtils.getLabelFont());
1111 help.setText(MessageManager.getString("action.help"));
1112 help.addActionListener(new ActionListener()
1115 public void actionPerformed(ActionEvent e)
1119 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1120 } catch (HelpSetException e1)
1122 e1.printStackTrace();
1126 help.setFont(JvSwingUtils.getLabelFont());
1127 help.setText(MessageManager.getString("action.help"));
1128 help.addActionListener(new ActionListener()
1131 public void actionPerformed(ActionEvent e)
1135 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1136 } catch (HelpSetException e1)
1138 e1.printStackTrace();
1142 cancel.setFont(JvSwingUtils.getLabelFont());
1143 cancel.setText(MessageManager.getString("action.cancel"));
1144 cancel.addActionListener(new ActionListener()
1147 public void actionPerformed(ActionEvent e)
1149 fr.setTransparency(originalTransparency);
1150 updateFeatureRenderer(originalData);
1154 ok.setFont(JvSwingUtils.getLabelFont());
1155 ok.setText(MessageManager.getString("action.ok"));
1156 ok.addActionListener(new ActionListener()
1159 public void actionPerformed(ActionEvent e)
1164 loadColours.setFont(JvSwingUtils.getLabelFont());
1165 loadColours.setText(MessageManager.getString("label.load_colours"));
1166 loadColours.addActionListener(new ActionListener()
1169 public void actionPerformed(ActionEvent e)
1174 saveColours.setFont(JvSwingUtils.getLabelFont());
1175 saveColours.setText(MessageManager.getString("label.save_colours"));
1176 saveColours.addActionListener(new ActionListener()
1179 public void actionPerformed(ActionEvent e)
1184 transparency.addChangeListener(new ChangeListener()
1187 public void stateChanged(ChangeEvent evt)
1189 fr.setTransparency((100 - transparency.getValue()) / 100f);
1190 af.alignPanel.paintAlignment(true);
1194 transparency.setMaximum(70);
1195 transparency.setToolTipText(MessageManager
1196 .getString("label.transparency_tip"));
1197 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1198 fetchDAS.addActionListener(new ActionListener()
1201 public void actionPerformed(ActionEvent e)
1203 fetchDAS_actionPerformed(e);
1206 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1207 saveDAS.addActionListener(new ActionListener()
1210 public void actionPerformed(ActionEvent e)
1212 saveDAS_actionPerformed(e);
1215 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1216 dasSettingsPane.setBorder(null);
1217 cancelDAS.setEnabled(false);
1218 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1219 cancelDAS.addActionListener(new ActionListener()
1222 public void actionPerformed(ActionEvent e)
1224 cancelDAS_actionPerformed(e);
1227 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1228 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1230 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1232 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1233 transbuttons.add(optimizeOrder);
1234 transbuttons.add(invert);
1235 transbuttons.add(sortByScore);
1236 transbuttons.add(sortByDens);
1237 transbuttons.add(help);
1238 JPanel sliderPanel = new JPanel();
1239 sliderPanel.add(transparency);
1240 transPanel.add(transparency);
1241 transPanel.add(transbuttons);
1242 buttonPanel.add(ok);
1243 buttonPanel.add(cancel);
1244 buttonPanel.add(loadColours);
1245 buttonPanel.add(saveColours);
1246 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1247 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1248 dasButtonPanel.add(fetchDAS);
1249 dasButtonPanel.add(cancelDAS);
1250 dasButtonPanel.add(saveDAS);
1251 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1252 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1255 public void fetchDAS_actionPerformed(ActionEvent e)
1257 fetchDAS.setEnabled(false);
1258 cancelDAS.setEnabled(true);
1259 dassourceBrowser.setGuiEnabled(false);
1260 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1261 .getSelectedSources();
1262 doDasFeatureFetch(selectedSources, true, true);
1266 * get the features from selectedSources for all or the current selection
1268 * @param selectedSources
1269 * @param checkDbRefs
1270 * @param promptFetchDbRefs
1272 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1273 boolean checkDbRefs, boolean promptFetchDbRefs)
1275 SequenceI[] dataset, seqs;
1277 AlignmentViewport vp = af.getViewport();
1278 if (vp.getSelectionGroup() != null
1279 && vp.getSelectionGroup().getSize() > 0)
1281 iSize = vp.getSelectionGroup().getSize();
1282 dataset = new SequenceI[iSize];
1283 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1287 iSize = vp.getAlignment().getHeight();
1288 seqs = vp.getAlignment().getSequencesArray();
1291 dataset = new SequenceI[iSize];
1292 for (int i = 0; i < iSize; i++)
1294 dataset[i] = seqs[i].getDatasetSequence();
1297 cancelDAS.setEnabled(true);
1298 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1299 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1300 af.getViewport().setShowSequenceFeatures(true);
1301 af.showSeqFeatures.setSelected(true);
1305 * blocking call to initialise the das source browser
1307 public void initDasSources()
1309 dassourceBrowser.initDasSources();
1313 * examine the current list of das sources and return any matching the given
1314 * nicknames in sources
1317 * Vector of Strings to resolve to DAS source nicknames.
1318 * @return sources that are present in source list.
1320 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1322 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1326 * get currently selected das sources. ensure you have called initDasSources
1327 * before calling this.
1329 * @return vector of selected das source nicknames
1331 public Vector<jalviewSourceI> getSelectedSources()
1333 return dassourceBrowser.getSelectedSources();
1337 * properly initialise DAS fetcher and then initiate a new thread to fetch
1338 * features from the named sources (rather than any turned on by default)
1342 * if true then runs in same thread, otherwise passes to the Swing
1345 public void fetchDasFeatures(Vector<String> sources, boolean block)
1348 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1349 .resolveSourceNicknames(sources);
1350 if (resolved.size() == 0)
1352 resolved = dassourceBrowser.getSelectedSources();
1354 if (resolved.size() > 0)
1356 final List<jalviewSourceI> dassources = resolved;
1357 fetchDAS.setEnabled(false);
1358 // cancelDAS.setEnabled(true); doDasFetch does this.
1359 Runnable fetcher = new Runnable()
1365 doDasFeatureFetch(dassources, true, false);
1375 SwingUtilities.invokeLater(fetcher);
1380 public void saveDAS_actionPerformed(ActionEvent e)
1383 .saveProperties(jalview.bin.Cache.applicationProperties);
1386 public void complete()
1388 fetchDAS.setEnabled(true);
1389 cancelDAS.setEnabled(false);
1390 dassourceBrowser.setGuiEnabled(true);
1394 public void cancelDAS_actionPerformed(ActionEvent e)
1396 if (dasFeatureFetcher != null)
1398 dasFeatureFetcher.cancel();
1403 public void noDasSourceActive()
1407 .showInternalConfirmDialog(
1410 .getString("label.no_das_sources_selected_warn"),
1412 .getString("label.no_das_sources_selected_title"),
1413 JOptionPane.DEFAULT_OPTION,
1414 JOptionPane.INFORMATION_MESSAGE);
1417 // ///////////////////////////////////////////////////////////////////////
1418 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1419 // ///////////////////////////////////////////////////////////////////////
1420 class FeatureTableModel extends AbstractTableModel
1422 FeatureTableModel(Object[][] data)
1427 private String[] columnNames = {
1428 MessageManager.getString("label.feature_type"),
1429 MessageManager.getString("action.colour"),
1430 MessageManager.getString("label.display") };
1432 private Object[][] data;
1434 public Object[][] getData()
1439 public void setData(Object[][] data)
1445 public int getColumnCount()
1447 return columnNames.length;
1450 public Object[] getRow(int row)
1456 public int getRowCount()
1462 public String getColumnName(int col)
1464 return columnNames[col];
1468 public Object getValueAt(int row, int col)
1470 return data[row][col];
1474 public Class getColumnClass(int c)
1476 return getValueAt(0, c).getClass();
1480 public boolean isCellEditable(int row, int col)
1482 return col == 0 ? false : true;
1486 public void setValueAt(Object value, int row, int col)
1488 data[row][col] = value;
1489 fireTableCellUpdated(row, col);
1490 updateFeatureRenderer(data);
1495 class ColorRenderer extends JLabel implements TableCellRenderer
1497 javax.swing.border.Border unselectedBorder = null;
1499 javax.swing.border.Border selectedBorder = null;
1501 final String baseTT = "Click to edit, right/apple click for menu.";
1503 public ColorRenderer()
1505 setOpaque(true); // MUST do this for background to show up.
1506 setHorizontalTextPosition(SwingConstants.CENTER);
1507 setVerticalTextPosition(SwingConstants.CENTER);
1511 public Component getTableCellRendererComponent(JTable tbl,
1512 Object color, boolean isSelected, boolean hasFocus, int row,
1515 FeatureColourI cellColour = (FeatureColourI) color;
1516 // JLabel comp = new JLabel();
1520 // setBounds(getBounds());
1522 setToolTipText(baseTT);
1523 setBackground(tbl.getBackground());
1524 if (!cellColour.isSimpleColour())
1526 Rectangle cr = tbl.getCellRect(row, column, false);
1527 FeatureSettings.renderGraduatedColor(this, cellColour,
1528 (int) cr.getWidth(), (int) cr.getHeight());
1535 newColor = cellColour.getColour();
1536 setBackground(newColor);
1540 if (selectedBorder == null)
1542 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1543 tbl.getSelectionBackground());
1545 setBorder(selectedBorder);
1549 if (unselectedBorder == null)
1551 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1552 tbl.getBackground());
1554 setBorder(unselectedBorder);
1562 * update comp using rendering settings from gcol
1567 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1569 int w = comp.getWidth(), h = comp.getHeight();
1572 w = (int) comp.getPreferredSize().getWidth();
1573 h = (int) comp.getPreferredSize().getHeight();
1580 renderGraduatedColor(comp, gcol, w, h);
1583 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1586 boolean thr = false;
1589 if (gcol.isAboveThreshold())
1593 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1595 if (gcol.isBelowThreshold())
1599 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1601 if (gcol.isColourByLabel())
1603 tt = "Coloured by label text. " + tt;
1613 Color newColor = gcol.getMaxColour();
1614 comp.setBackground(newColor);
1615 // System.err.println("Width is " + w / 2);
1616 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1617 comp.setIcon(ficon);
1618 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1619 // + newColor.getGreen() + ", " + newColor.getBlue()
1620 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1621 // + ", " + minCol.getBlue() + ")");
1623 comp.setHorizontalAlignment(SwingConstants.CENTER);
1625 if (tt.length() > 0)
1627 if (comp.getToolTipText() == null)
1629 comp.setToolTipText(tt);
1633 comp.setToolTipText(tt + " " + comp.getToolTipText());
1639 class FeatureIcon implements Icon
1641 FeatureColourI gcol;
1645 boolean midspace = false;
1647 int width = 50, height = 20;
1649 int s1, e1; // start and end of midpoint band for thresholded symbol
1651 Color mpcolour = Color.white;
1653 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1673 public int getIconWidth()
1679 public int getIconHeight()
1685 public void paintIcon(Component c, Graphics g, int x, int y)
1688 if (gcol.isColourByLabel())
1691 g.fillRect(0, 0, width, height);
1692 // need an icon here.
1693 g.setColor(gcol.getMaxColour());
1695 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1697 // g.setFont(g.getFont().deriveFont(
1698 // AffineTransform.getScaleInstance(
1699 // width/g.getFontMetrics().stringWidth("Label"),
1700 // height/g.getFontMetrics().getHeight())));
1702 g.drawString(MessageManager.getString("label.label"), 0, 0);
1707 Color minCol = gcol.getMinColour();
1709 g.fillRect(0, 0, s1, height);
1712 g.setColor(Color.white);
1713 g.fillRect(s1, 0, e1 - s1, height);
1715 g.setColor(gcol.getMaxColour());
1716 g.fillRect(0, e1, width - e1, height);
1721 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1726 FeatureColourI currentColor;
1728 FeatureColourChooser chooser;
1734 JColorChooser colorChooser;
1738 protected static final String EDIT = "edit";
1740 int selectedRow = 0;
1742 public ColorEditor(FeatureSettings me)
1745 // Set up the editor (from the table's point of view),
1746 // which is a button.
1747 // This button brings up the color chooser dialog,
1748 // which is the editor from the user's point of view.
1749 button = new JButton();
1750 button.setActionCommand(EDIT);
1751 button.addActionListener(this);
1752 button.setBorderPainted(false);
1753 // Set up the dialog that the button brings up.
1754 colorChooser = new JColorChooser();
1755 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1756 colorChooser, this, // OK button handler
1757 null); // no CANCEL button handler
1761 * Handles events from the editor button and from the dialog's OK button.
1764 public void actionPerformed(ActionEvent e)
1767 if (EDIT.equals(e.getActionCommand()))
1769 // The user has clicked the cell, so
1770 // bring up the dialog.
1771 if (currentColor.isSimpleColour())
1773 // bring up simple color chooser
1774 button.setBackground(currentColor.getColour());
1775 colorChooser.setColor(currentColor.getColour());
1776 dialog.setVisible(true);
1780 // bring up graduated chooser.
1781 chooser = new FeatureColourChooser(me.fr, type);
1782 chooser.setRequestFocusEnabled(true);
1783 chooser.requestFocus();
1784 chooser.addActionListener(this);
1786 // Make the renderer reappear.
1787 fireEditingStopped();
1791 { // User pressed dialog's "OK" button.
1792 if (currentColor.isSimpleColour())
1794 currentColor = new FeatureColour(colorChooser.getColor());
1798 currentColor = chooser.getLastColour();
1800 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1801 fireEditingStopped();
1802 me.table.validate();
1806 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1808 public Object getCellEditorValue()
1810 return currentColor;
1813 // Implement the one method defined by TableCellEditor.
1815 public Component getTableCellEditorComponent(JTable table, Object value,
1816 boolean isSelected, int row, int column)
1818 currentColor = (FeatureColourI) value;
1819 this.selectedRow = row;
1820 type = me.table.getValueAt(row, 0).toString();
1821 button.setOpaque(true);
1822 button.setBackground(me.getBackground());
1823 if (!currentColor.isSimpleColour())
1825 JLabel btn = new JLabel();
1826 btn.setSize(button.getSize());
1827 FeatureSettings.renderGraduatedColor(btn, currentColor);
1828 button.setBackground(btn.getBackground());
1829 button.setIcon(btn.getIcon());
1830 button.setText(btn.getText());
1835 button.setIcon(null);
1836 button.setBackground(currentColor.getColour());