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.Colour;
32 import jalview.schemes.FeatureColour;
33 import jalview.util.ColorUtils;
34 import jalview.util.Format;
35 import jalview.util.MessageManager;
36 import jalview.util.Platform;
37 import jalview.util.QuickSort;
38 import jalview.viewmodel.AlignmentViewport;
39 import jalview.ws.dbsources.das.api.jalviewSourceI;
41 import java.awt.BorderLayout;
42 import java.awt.Color;
43 import java.awt.Component;
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.Hashtable;
65 import java.util.Iterator;
66 import java.util.List;
69 import java.util.Vector;
71 import javax.help.HelpSetException;
72 import javax.swing.AbstractCellEditor;
73 import javax.swing.BorderFactory;
74 import javax.swing.Icon;
75 import javax.swing.JButton;
76 import javax.swing.JCheckBox;
77 import javax.swing.JCheckBoxMenuItem;
78 import javax.swing.JColorChooser;
79 import javax.swing.JDialog;
80 import javax.swing.JInternalFrame;
81 import javax.swing.JLabel;
82 import javax.swing.JLayeredPane;
83 import javax.swing.JMenuItem;
84 import javax.swing.JOptionPane;
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 public FeatureSettings(AlignFrame af)
134 fr = af.getFeatureRenderer();
135 // allow transparency to be recovered
136 transparency.setMaximum(100 - (int) ((originalTransparency = fr
137 .getTransparency()) * 100));
142 } catch (Exception ex)
144 ex.printStackTrace();
150 public String getToolTipText(MouseEvent e)
152 if (table.columnAtPoint(e.getPoint()) == 0)
155 * Tooltip for feature name only
157 return JvSwingUtils.wrapTooltip(true, MessageManager
158 .getString("label.feature_settings_click_drag"));
163 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
164 table.setFont(new Font("Verdana", Font.PLAIN, 12));
165 table.setDefaultRenderer(Color.class, new ColorRenderer());
167 table.setDefaultEditor(Color.class, new ColorEditor(this));
169 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
170 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
171 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
173 table.addMouseListener(new MouseAdapter()
176 public void mousePressed(MouseEvent evt)
178 selectedRow = table.rowAtPoint(evt.getPoint());
179 if (evt.isPopupTrigger())
181 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
182 table.getValueAt(selectedRow, 1), fr.getMinMax(),
183 evt.getX(), evt.getY());
185 else if (evt.getClickCount() == 2)
187 boolean invertSelection = evt.isAltDown();
188 boolean toggleSelection = Platform.isControlDown(evt);
189 boolean extendSelection = evt.isShiftDown();
190 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
191 invertSelection, extendSelection, toggleSelection,
192 (String) table.getValueAt(selectedRow, 0));
196 // isPopupTrigger fires on mouseReleased on Windows
198 public void mouseReleased(MouseEvent evt)
200 selectedRow = table.rowAtPoint(evt.getPoint());
201 if (evt.isPopupTrigger())
203 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
204 table.getValueAt(selectedRow, 1), fr.getMinMax(),
205 evt.getX(), evt.getY());
210 table.addMouseMotionListener(new MouseMotionAdapter()
213 public void mouseDragged(MouseEvent evt)
215 int newRow = table.rowAtPoint(evt.getPoint());
216 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
219 * reposition 'selectedRow' to 'newRow' (the dragged to location)
220 * this could be more than one row away for a very fast drag action
221 * so just swap it with adjacent rows until we get it there
223 Object[][] data = ((FeatureTableModel) table.getModel())
225 int direction = newRow < selectedRow ? -1 : 1;
226 for (int i = selectedRow; i != newRow; i += direction)
228 Object[] temp = data[i];
229 data[i] = data[i + direction];
230 data[i + direction] = temp;
232 updateFeatureRenderer(data);
234 selectedRow = newRow;
238 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
239 // MessageManager.getString("label.feature_settings_click_drag")));
240 scrollPane.setViewportView(table);
242 dassourceBrowser = new DasSourceBrowser(this);
243 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
245 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
247 fr.findAllFeatures(true); // display everything!
250 discoverAllFeatureData();
251 final PropertyChangeListener change;
252 final FeatureSettings fs = this;
253 fr.addPropertyChangeListener(change = new PropertyChangeListener()
256 public void propertyChange(PropertyChangeEvent evt)
258 if (!fs.resettingTable && !fs.handlingUpdate)
260 fs.handlingUpdate = true;
261 fs.resetTable(null); // new groups may be added with new seuqence
262 // feature types only
263 fs.handlingUpdate = false;
269 frame = new JInternalFrame();
270 frame.setContentPane(this);
271 if (Platform.isAMac())
273 Desktop.addInternalFrame(frame,
274 MessageManager.getString("label.sequence_feature_settings"),
279 Desktop.addInternalFrame(frame,
280 MessageManager.getString("label.sequence_feature_settings"),
284 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
287 public void internalFrameClosed(
288 javax.swing.event.InternalFrameEvent evt)
290 fr.removePropertyChangeListener(change);
291 dassourceBrowser.fs = null;
294 frame.setLayer(JLayeredPane.PALETTE_LAYER);
297 protected void popupSort(final int selectedRow, final String type,
298 final Object typeCol, final Map<String, float[][]> minmax, int x,
301 final FeatureColourI featureColour = (FeatureColourI) typeCol;
303 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
304 "label.settings_for_param", new String[] { type }));
305 JMenuItem scr = new JMenuItem(
306 MessageManager.getString("label.sort_by_score"));
308 final FeatureSettings me = this;
309 scr.addActionListener(new ActionListener()
313 public void actionPerformed(ActionEvent e)
315 me.af.avc.sortAlignmentByFeatureScore(Arrays
316 .asList(new String[] { type }));
320 JMenuItem dens = new JMenuItem(
321 MessageManager.getString("label.sort_by_density"));
322 dens.addActionListener(new ActionListener()
326 public void actionPerformed(ActionEvent e)
328 me.af.avc.sortAlignmentByFeatureDensity(Arrays
329 .asList(new String[] { type }));
336 final float[][] typeMinMax = minmax.get(type);
338 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
339 * this is broken at the moment and isn't that useful anyway!
340 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
343 * public void actionPerformed(ActionEvent e) {
344 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
345 * null); } else { minmax.put(type, typeMinMax); } }
351 if (typeMinMax != null && typeMinMax[0] != null)
353 // if (table.getValueAt(row, column));
354 // graduated colourschemes for those where minmax exists for the
355 // positional features
356 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
358 mxcol.setSelected(!featureColour.isSimpleColour());
360 mxcol.addActionListener(new ActionListener()
362 JColorChooser colorChooser;
365 public void actionPerformed(ActionEvent e)
367 if (e.getSource() == mxcol)
369 if (featureColour.isSimpleColour())
371 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
373 fc.addActionListener(this);
377 // bring up simple color chooser
378 colorChooser = new JColorChooser();
379 JDialog dialog = JColorChooser.createDialog(me,
380 "Select new Colour", true, // modal
381 colorChooser, this, // OK button handler
382 null); // no CANCEL button handler
383 colorChooser.setColor(ColorUtils.getColor(featureColour
385 dialog.setVisible(true);
390 if (e.getSource() instanceof FeatureColourChooser)
392 FeatureColourChooser fc = (FeatureColourChooser) e
394 table.setValueAt(fc.getLastColour(), selectedRow, 1);
399 // probably the color chooser!
401 new FeatureColour(colorChooser.getColor()),
404 me.updateFeatureRenderer(
405 ((FeatureTableModel) table.getModel()).getData(),
414 JMenuItem selCols = new JMenuItem(
415 MessageManager.getString("label.select_columns_containing"));
416 selCols.addActionListener(new ActionListener()
419 public void actionPerformed(ActionEvent arg0)
421 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
425 JMenuItem clearCols = new JMenuItem(
426 MessageManager.getString("label.select_columns_not_containing"));
427 clearCols.addActionListener(new ActionListener()
430 public void actionPerformed(ActionEvent arg0)
432 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
436 JMenuItem hideCols = new JMenuItem(
437 MessageManager.getString("label.hide_columns_containing"));
438 hideCols.addActionListener(new ActionListener()
441 public void actionPerformed(ActionEvent arg0)
443 fr.ap.alignFrame.hideFeatureColumns(type, true);
446 JMenuItem hideOtherCols = new JMenuItem(
447 MessageManager.getString("label.hide_columns_not_containing"));
448 hideOtherCols.addActionListener(new ActionListener()
451 public void actionPerformed(ActionEvent arg0)
453 fr.ap.alignFrame.hideFeatureColumns(type, false);
459 men.add(hideOtherCols);
460 men.show(table, x, y);
464 * true when Feature Settings are updating from feature renderer
466 private boolean handlingUpdate = false;
469 * contains a float[3] for each feature type string. created by setTableData
471 Map<String, float[]> typeWidth = null;
474 synchronized public void discoverAllFeatureData()
476 Vector<String> allFeatures = new Vector<String>();
477 Vector<String> allGroups = new Vector<String>();
478 SequenceFeature[] tmpfeatures;
480 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
482 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
483 .getSequenceFeatures();
484 if (tmpfeatures == null)
490 while (index < tmpfeatures.length)
492 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
498 if (tmpfeatures[index].getFeatureGroup() != null)
500 group = tmpfeatures[index].featureGroup;
501 if (!allGroups.contains(group))
503 allGroups.addElement(group);
504 checkGroupState(group);
508 if (!allFeatures.contains(tmpfeatures[index].getType()))
510 allFeatures.addElement(tmpfeatures[index].getType());
522 * Synchronise gui group list and check visibility of group
525 * @return true if group is visible
527 private boolean checkGroupState(String group)
529 boolean visible = fr.checkGroupVisibility(group, true);
531 if (groupPanel == null)
533 groupPanel = new JPanel();
536 boolean alreadyAdded = false;
537 for (int g = 0; g < groupPanel.getComponentCount(); g++)
539 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
542 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
552 final String grp = group;
553 final JCheckBox check = new JCheckBox(group, visible);
554 check.setFont(new Font("Serif", Font.BOLD, 12));
555 check.addItemListener(new ItemListener()
558 public void itemStateChanged(ItemEvent evt)
560 fr.setGroupVisibility(check.getText(), check.isSelected());
561 af.alignPanel.getSeqPanel().seqCanvas.repaint();
562 if (af.alignPanel.overviewPanel != null)
564 af.alignPanel.overviewPanel.updateOverviewImage();
567 resetTable(new String[] { grp });
570 groupPanel.add(check);
574 boolean resettingTable = false;
576 synchronized void resetTable(String[] groupChanged)
578 if (resettingTable == true)
582 resettingTable = true;
583 typeWidth = new Hashtable<String, float[]>();
584 // TODO: change avWidth calculation to 'per-sequence' average and use long
586 float[] avWidth = null;
587 SequenceFeature[] tmpfeatures;
588 String group = null, type;
589 Vector<String> visibleChecks = new Vector<String>();
591 // Find out which features should be visible depending on which groups
592 // are selected / deselected
593 // and recompute average width ordering
594 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
597 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
598 .getSequenceFeatures();
599 if (tmpfeatures == null)
605 while (index < tmpfeatures.length)
607 group = tmpfeatures[index].featureGroup;
609 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
615 if (group == null || checkGroupState(group))
617 type = tmpfeatures[index].getType();
618 if (!visibleChecks.contains(type))
620 visibleChecks.addElement(type);
623 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
625 typeWidth.put(tmpfeatures[index].getType(),
626 avWidth = new float[3]);
630 avWidth = typeWidth.get(tmpfeatures[index].getType());
633 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
635 avWidth[1] += 1 + tmpfeatures[index].getBegin()
636 - tmpfeatures[index].getEnd();
640 avWidth[1] += 1 + tmpfeatures[index].getEnd()
641 - tmpfeatures[index].getBegin();
647 int fSize = visibleChecks.size();
648 Object[][] data = new Object[fSize][3];
651 if (fr.hasRenderOrder())
655 fr.findAllFeatures(groupChanged != null); // prod to update
656 // colourschemes. but don't
658 // First add the checks in the previous render order,
659 // in case the window has been closed and reopened
661 List<String> frl = fr.getRenderOrder();
662 for (int ro = frl.size() - 1; ro > -1; ro--)
666 if (!visibleChecks.contains(type))
671 data[dataIndex][0] = type;
672 data[dataIndex][1] = fr.getFeatureStyle(type);
673 data[dataIndex][2] = new Boolean(af.getViewport()
674 .getFeaturesDisplayed().isVisible(type));
676 visibleChecks.removeElement(type);
680 fSize = visibleChecks.size();
681 for (int i = 0; i < fSize; i++)
683 // These must be extra features belonging to the group
684 // which was just selected
685 type = visibleChecks.elementAt(i).toString();
686 data[dataIndex][0] = type;
688 data[dataIndex][1] = fr.getFeatureStyle(type);
689 if (data[dataIndex][1] == null)
691 // "Colour has been updated in another view!!"
692 fr.clearRenderOrder();
696 data[dataIndex][2] = new Boolean(true);
700 if (originalData == null)
702 originalData = new Object[data.length][3];
703 for (int i = 0; i < data.length; i++)
705 System.arraycopy(data[i], 0, originalData[i], 0, 3);
709 table.setModel(new FeatureTableModel(data));
710 table.getColumnModel().getColumn(0).setPreferredWidth(200);
712 if (groupPanel != null)
714 groupPanel.setLayout(new GridLayout(
715 fr.getFeatureGroupsSize() / 4 + 1, 4));
717 groupPanel.validate();
718 bigPanel.add(groupPanel, BorderLayout.NORTH);
721 updateFeatureRenderer(data, groupChanged != null);
722 resettingTable = false;
726 * reorder data based on the featureRenderers global priority list.
730 private void ensureOrder(Object[][] data)
732 boolean sort = false;
733 float[] order = new float[data.length];
734 for (int i = 0; i < order.length; i++)
736 order[i] = fr.getOrder(data[i][0].toString());
739 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
743 sort = sort || order[i - 1] > order[i];
748 jalview.util.QuickSort.sort(order, data);
754 JalviewFileChooser chooser = new JalviewFileChooser(
755 jalview.bin.Cache.getProperty("LAST_DIRECTORY"),
756 new String[] { "fc" },
757 new String[] { "Sequence Feature Colours" },
758 "Sequence Feature Colours");
759 chooser.setFileView(new jalview.io.JalviewFileView());
760 chooser.setDialogTitle(MessageManager
761 .getString("label.load_feature_colours"));
762 chooser.setToolTipText(MessageManager.getString("action.load"));
764 int value = chooser.showOpenDialog(this);
766 if (value == JalviewFileChooser.APPROVE_OPTION)
768 File file = chooser.getSelectedFile();
772 InputStreamReader in = new InputStreamReader(new FileInputStream(
775 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
777 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
780 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
783 Color mincol = null, maxcol = null;
786 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
787 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
789 } catch (Exception e)
791 Cache.log.warn("Couldn't parse out graduated feature color.",
794 FeatureColourI gcol = new FeatureColour(new Colour(mincol),
796 newcol.getMin(), newcol.getMax());
797 if (newcol.hasAutoScale())
799 gcol.setAutoScaled(newcol.getAutoScale());
801 if (newcol.hasColourByLabel())
803 gcol.setColourByLabel(newcol.getColourByLabel());
805 if (newcol.hasThreshold())
807 gcol.setThreshold(newcol.getThreshold());
809 if (newcol.getThreshType().length() > 0)
811 String ttyp = newcol.getThreshType();
812 if (ttyp.equalsIgnoreCase("ABOVE"))
814 gcol.setAboveThreshold(true);
816 if (ttyp.equalsIgnoreCase("BELOW"))
818 gcol.setBelowThreshold(true);
821 fr.setColour(name = newcol.getName(), gcol);
825 Color color = new Color(
826 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
827 fr.setColour(name = jucs.getColour(i).getName(),
828 new FeatureColour(new Colour(color)));
830 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
835 Object[][] data = ((FeatureTableModel) table.getModel())
838 updateFeatureRenderer(data, false);
841 } catch (Exception ex)
843 System.out.println("Error loading User Colour File\n" + ex);
850 JalviewFileChooser chooser = new JalviewFileChooser(
851 Cache.getProperty("LAST_DIRECTORY"),
852 new String[] { "fc" },
853 new String[] { "Sequence Feature Colours" },
854 "Sequence Feature Colours");
855 chooser.setFileView(new jalview.io.JalviewFileView());
856 chooser.setDialogTitle(MessageManager
857 .getString("label.save_feature_colours"));
858 chooser.setToolTipText(MessageManager.getString("action.save"));
860 int value = chooser.showSaveDialog(this);
862 if (value == JalviewFileChooser.APPROVE_OPTION)
864 String choice = chooser.getSelectedFile().getPath();
865 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
866 ucs.setSchemeName("Sequence Features");
869 PrintWriter out = new PrintWriter(new OutputStreamWriter(
870 new FileOutputStream(choice), "UTF-8"));
872 Set<String> fr_colours = fr.getAllFeatureColours();
873 Iterator<String> e = fr_colours.iterator();
874 float[] sortOrder = new float[fr_colours.size()];
875 String[] sortTypes = new String[fr_colours.size()];
879 sortTypes[i] = e.next();
880 sortOrder[i] = fr.getOrder(sortTypes[i]);
883 QuickSort.sort(sortOrder, sortTypes);
885 for (i = 0; i < sortTypes.length; i++)
887 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
888 col.setName(sortTypes[i]);
889 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
890 if (fcol.isSimpleColour())
892 col.setRGB(Format.getHexString(fcol.getColour()));
896 col.setRGB(Format.getHexString(fcol.getMaxColour()));
897 col.setMin(fcol.getMin());
898 col.setMax(fcol.getMax());
899 col.setMinRGB(jalview.util.Format.getHexString(fcol
901 col.setAutoScale(fcol.isAutoScaled());
902 col.setThreshold(fcol.getThreshold());
903 col.setColourByLabel(fcol.isColourByLabel());
904 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
905 .isBelowThreshold() ? "BELOW" : "NONE"));
911 } catch (Exception ex)
913 ex.printStackTrace();
918 public void invertSelection()
920 for (int i = 0; i < table.getRowCount(); i++)
922 Boolean value = (Boolean) table.getValueAt(i, 2);
924 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
928 public void orderByAvWidth()
930 if (table == null || table.getModel() == null)
934 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
935 float[] width = new float[data.length];
939 for (int i = 0; i < data.length; i++)
941 awidth = typeWidth.get(data[i][0]);
944 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
945 // weight - but have to make per
946 // sequence, too (awidth[2])
947 // if (width[i]==1) // hack to distinguish single width sequences.
959 boolean sort = false;
960 for (int i = 0; i < width.length; i++)
962 // awidth = (float[]) typeWidth.get(data[i][0]);
965 width[i] = fr.getOrder(data[i][0].toString());
968 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
973 width[i] /= max; // normalize
974 fr.setOrder(data[i][0].toString(), width[i]); // store for later
978 sort = sort || width[i - 1] > width[i];
983 jalview.util.QuickSort.sort(width, data);
984 // update global priority order
987 updateFeatureRenderer(data, false);
995 frame.setClosed(true);
996 } catch (Exception exe)
1002 public void updateFeatureRenderer(Object[][] data)
1004 updateFeatureRenderer(data, true);
1008 * Update the priority order of features; only repaint if this changed the
1009 * order of visible features
1014 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1016 if (fr.setFeaturePriority(data, visibleNew))
1018 af.alignPanel.paintAlignment(true);
1022 int selectedRow = -1;
1024 JTabbedPane tabbedPane = new JTabbedPane();
1026 BorderLayout borderLayout1 = new BorderLayout();
1028 BorderLayout borderLayout2 = new BorderLayout();
1030 BorderLayout borderLayout3 = new BorderLayout();
1032 JPanel bigPanel = new JPanel();
1034 BorderLayout borderLayout4 = new BorderLayout();
1036 JButton invert = new JButton();
1038 JPanel buttonPanel = new JPanel();
1040 JButton cancel = new JButton();
1042 JButton ok = new JButton();
1044 JButton loadColours = new JButton();
1046 JButton saveColours = new JButton();
1048 JPanel dasButtonPanel = new JPanel();
1050 JButton fetchDAS = new JButton();
1052 JButton saveDAS = new JButton();
1054 JButton cancelDAS = new JButton();
1056 JButton optimizeOrder = new JButton();
1058 JButton sortByScore = new JButton();
1060 JButton sortByDens = new JButton();
1062 JButton help = new JButton();
1064 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1066 private void jbInit() throws Exception
1068 this.setLayout(borderLayout1);
1069 settingsPane.setLayout(borderLayout2);
1070 dasSettingsPane.setLayout(borderLayout3);
1071 bigPanel.setLayout(borderLayout4);
1072 invert.setFont(JvSwingUtils.getLabelFont());
1073 invert.setText(MessageManager.getString("label.invert_selection"));
1074 invert.addActionListener(new ActionListener()
1077 public void actionPerformed(ActionEvent e)
1082 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1083 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1084 optimizeOrder.addActionListener(new ActionListener()
1087 public void actionPerformed(ActionEvent e)
1092 sortByScore.setFont(JvSwingUtils.getLabelFont());
1094 .setText(MessageManager.getString("label.seq_sort_by_score"));
1095 sortByScore.addActionListener(new ActionListener()
1098 public void actionPerformed(ActionEvent e)
1100 af.avc.sortAlignmentByFeatureScore(null);
1103 sortByDens.setFont(JvSwingUtils.getLabelFont());
1104 sortByDens.setText(MessageManager
1105 .getString("label.sequence_sort_by_density"));
1106 sortByDens.addActionListener(new ActionListener()
1109 public void actionPerformed(ActionEvent e)
1111 af.avc.sortAlignmentByFeatureDensity(null);
1114 help.setFont(JvSwingUtils.getLabelFont());
1115 help.setText(MessageManager.getString("action.help"));
1116 help.addActionListener(new ActionListener()
1119 public void actionPerformed(ActionEvent e)
1123 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1124 } catch (HelpSetException e1)
1126 e1.printStackTrace();
1130 help.setFont(JvSwingUtils.getLabelFont());
1131 help.setText(MessageManager.getString("action.help"));
1132 help.addActionListener(new ActionListener()
1135 public void actionPerformed(ActionEvent e)
1139 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1140 } catch (HelpSetException e1)
1142 e1.printStackTrace();
1146 cancel.setFont(JvSwingUtils.getLabelFont());
1147 cancel.setText(MessageManager.getString("action.cancel"));
1148 cancel.addActionListener(new ActionListener()
1151 public void actionPerformed(ActionEvent e)
1153 fr.setTransparency(originalTransparency);
1154 updateFeatureRenderer(originalData);
1158 ok.setFont(JvSwingUtils.getLabelFont());
1159 ok.setText(MessageManager.getString("action.ok"));
1160 ok.addActionListener(new ActionListener()
1163 public void actionPerformed(ActionEvent e)
1168 loadColours.setFont(JvSwingUtils.getLabelFont());
1169 loadColours.setText(MessageManager.getString("label.load_colours"));
1170 loadColours.addActionListener(new ActionListener()
1173 public void actionPerformed(ActionEvent e)
1178 saveColours.setFont(JvSwingUtils.getLabelFont());
1179 saveColours.setText(MessageManager.getString("label.save_colours"));
1180 saveColours.addActionListener(new ActionListener()
1183 public void actionPerformed(ActionEvent e)
1188 transparency.addChangeListener(new ChangeListener()
1191 public void stateChanged(ChangeEvent evt)
1193 fr.setTransparency((100 - transparency.getValue()) / 100f);
1194 af.alignPanel.paintAlignment(true);
1198 transparency.setMaximum(70);
1199 transparency.setToolTipText(MessageManager
1200 .getString("label.transparency_tip"));
1201 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1202 fetchDAS.addActionListener(new ActionListener()
1205 public void actionPerformed(ActionEvent e)
1207 fetchDAS_actionPerformed(e);
1210 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1211 saveDAS.addActionListener(new ActionListener()
1214 public void actionPerformed(ActionEvent e)
1216 saveDAS_actionPerformed(e);
1219 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1220 dasSettingsPane.setBorder(null);
1221 cancelDAS.setEnabled(false);
1222 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1223 cancelDAS.addActionListener(new ActionListener()
1226 public void actionPerformed(ActionEvent e)
1228 cancelDAS_actionPerformed(e);
1231 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1232 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1234 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1236 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1237 transbuttons.add(optimizeOrder);
1238 transbuttons.add(invert);
1239 transbuttons.add(sortByScore);
1240 transbuttons.add(sortByDens);
1241 transbuttons.add(help);
1242 JPanel sliderPanel = new JPanel();
1243 sliderPanel.add(transparency);
1244 transPanel.add(transparency);
1245 transPanel.add(transbuttons);
1246 buttonPanel.add(ok);
1247 buttonPanel.add(cancel);
1248 buttonPanel.add(loadColours);
1249 buttonPanel.add(saveColours);
1250 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1251 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1252 dasButtonPanel.add(fetchDAS);
1253 dasButtonPanel.add(cancelDAS);
1254 dasButtonPanel.add(saveDAS);
1255 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1256 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1259 public void fetchDAS_actionPerformed(ActionEvent e)
1261 fetchDAS.setEnabled(false);
1262 cancelDAS.setEnabled(true);
1263 dassourceBrowser.setGuiEnabled(false);
1264 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1265 .getSelectedSources();
1266 doDasFeatureFetch(selectedSources, true, true);
1270 * get the features from selectedSources for all or the current selection
1272 * @param selectedSources
1273 * @param checkDbRefs
1274 * @param promptFetchDbRefs
1276 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1277 boolean checkDbRefs, boolean promptFetchDbRefs)
1279 SequenceI[] dataset, seqs;
1281 AlignmentViewport vp = af.getViewport();
1282 if (vp.getSelectionGroup() != null
1283 && vp.getSelectionGroup().getSize() > 0)
1285 iSize = vp.getSelectionGroup().getSize();
1286 dataset = new SequenceI[iSize];
1287 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1291 iSize = vp.getAlignment().getHeight();
1292 seqs = vp.getAlignment().getSequencesArray();
1295 dataset = new SequenceI[iSize];
1296 for (int i = 0; i < iSize; i++)
1298 dataset[i] = seqs[i].getDatasetSequence();
1301 cancelDAS.setEnabled(true);
1302 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1303 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1304 af.getViewport().setShowSequenceFeatures(true);
1305 af.showSeqFeatures.setSelected(true);
1309 * blocking call to initialise the das source browser
1311 public void initDasSources()
1313 dassourceBrowser.initDasSources();
1317 * examine the current list of das sources and return any matching the given
1318 * nicknames in sources
1321 * Vector of Strings to resolve to DAS source nicknames.
1322 * @return sources that are present in source list.
1324 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1326 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1330 * get currently selected das sources. ensure you have called initDasSources
1331 * before calling this.
1333 * @return vector of selected das source nicknames
1335 public Vector<jalviewSourceI> getSelectedSources()
1337 return dassourceBrowser.getSelectedSources();
1341 * properly initialise DAS fetcher and then initiate a new thread to fetch
1342 * features from the named sources (rather than any turned on by default)
1346 * if true then runs in same thread, otherwise passes to the Swing
1349 public void fetchDasFeatures(Vector<String> sources, boolean block)
1352 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1353 .resolveSourceNicknames(sources);
1354 if (resolved.size() == 0)
1356 resolved = dassourceBrowser.getSelectedSources();
1358 if (resolved.size() > 0)
1360 final List<jalviewSourceI> dassources = resolved;
1361 fetchDAS.setEnabled(false);
1362 // cancelDAS.setEnabled(true); doDasFetch does this.
1363 Runnable fetcher = new Runnable()
1369 doDasFeatureFetch(dassources, true, false);
1379 SwingUtilities.invokeLater(fetcher);
1384 public void saveDAS_actionPerformed(ActionEvent e)
1387 .saveProperties(jalview.bin.Cache.applicationProperties);
1390 public void complete()
1392 fetchDAS.setEnabled(true);
1393 cancelDAS.setEnabled(false);
1394 dassourceBrowser.setGuiEnabled(true);
1398 public void cancelDAS_actionPerformed(ActionEvent e)
1400 if (dasFeatureFetcher != null)
1402 dasFeatureFetcher.cancel();
1407 public void noDasSourceActive()
1411 .showInternalConfirmDialog(
1414 .getString("label.no_das_sources_selected_warn"),
1416 .getString("label.no_das_sources_selected_title"),
1417 JOptionPane.DEFAULT_OPTION,
1418 JOptionPane.INFORMATION_MESSAGE);
1421 // ///////////////////////////////////////////////////////////////////////
1422 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1423 // ///////////////////////////////////////////////////////////////////////
1424 class FeatureTableModel extends AbstractTableModel
1426 FeatureTableModel(Object[][] data)
1431 private String[] columnNames = {
1432 MessageManager.getString("label.feature_type"),
1433 MessageManager.getString("action.colour"),
1434 MessageManager.getString("label.display") };
1436 private Object[][] data;
1438 public Object[][] getData()
1443 public void setData(Object[][] data)
1449 public int getColumnCount()
1451 return columnNames.length;
1454 public Object[] getRow(int row)
1460 public int getRowCount()
1466 public String getColumnName(int col)
1468 return columnNames[col];
1472 public Object getValueAt(int row, int col)
1474 return data[row][col];
1478 public Class getColumnClass(int c)
1480 return getValueAt(0, c).getClass();
1484 public boolean isCellEditable(int row, int col)
1486 return col == 0 ? false : true;
1490 public void setValueAt(Object value, int row, int col)
1492 data[row][col] = value;
1493 fireTableCellUpdated(row, col);
1494 updateFeatureRenderer(data);
1499 class ColorRenderer extends JLabel implements TableCellRenderer
1501 javax.swing.border.Border unselectedBorder = null;
1503 javax.swing.border.Border selectedBorder = null;
1505 final String baseTT = "Click to edit, right/apple click for menu.";
1507 public ColorRenderer()
1509 setOpaque(true); // MUST do this for background to show up.
1510 setHorizontalTextPosition(SwingConstants.CENTER);
1511 setVerticalTextPosition(SwingConstants.CENTER);
1515 public Component getTableCellRendererComponent(JTable tbl,
1516 Object color, boolean isSelected, boolean hasFocus, int row,
1519 FeatureColourI cellColour = (FeatureColourI) color;
1520 // JLabel comp = new JLabel();
1524 // setBounds(getBounds());
1526 setToolTipText(baseTT);
1527 setBackground(tbl.getBackground());
1528 if (!cellColour.isSimpleColour())
1530 Rectangle cr = tbl.getCellRect(row, column, false);
1531 FeatureSettings.renderGraduatedColor(this, cellColour,
1532 (int) cr.getWidth(), (int) cr.getHeight());
1539 newColor = ColorUtils.getColor(cellColour.getColour());
1540 setBackground(newColor);
1544 if (selectedBorder == null)
1546 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1547 tbl.getSelectionBackground());
1549 setBorder(selectedBorder);
1553 if (unselectedBorder == null)
1555 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1556 tbl.getBackground());
1558 setBorder(unselectedBorder);
1566 * update comp using rendering settings from gcol
1571 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1573 int w = comp.getWidth(), h = comp.getHeight();
1576 w = (int) comp.getPreferredSize().getWidth();
1577 h = (int) comp.getPreferredSize().getHeight();
1584 renderGraduatedColor(comp, gcol, w, h);
1587 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1590 boolean thr = false;
1593 if (gcol.isAboveThreshold())
1597 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1599 if (gcol.isBelowThreshold())
1603 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1605 if (gcol.isColourByLabel())
1607 tt = "Coloured by label text. " + tt;
1617 Color newColor = ColorUtils.getColor(gcol.getMaxColour());
1618 comp.setBackground(newColor);
1619 // System.err.println("Width is " + w / 2);
1620 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1621 comp.setIcon(ficon);
1622 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1623 // + newColor.getGreen() + ", " + newColor.getBlue()
1624 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1625 // + ", " + minCol.getBlue() + ")");
1627 comp.setHorizontalAlignment(SwingConstants.CENTER);
1629 if (tt.length() > 0)
1631 if (comp.getToolTipText() == null)
1633 comp.setToolTipText(tt);
1637 comp.setToolTipText(tt + " " + comp.getToolTipText());
1643 class FeatureIcon implements Icon
1645 FeatureColourI gcol;
1649 boolean midspace = false;
1651 int width = 50, height = 20;
1653 int s1, e1; // start and end of midpoint band for thresholded symbol
1655 Color mpcolour = Color.white;
1657 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1677 public int getIconWidth()
1683 public int getIconHeight()
1689 public void paintIcon(Component c, Graphics g, int x, int y)
1692 if (gcol.isColourByLabel())
1695 g.fillRect(0, 0, width, height);
1696 // need an icon here.
1697 g.setColor(ColorUtils.getColor(gcol.getMaxColour()));
1699 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1701 // g.setFont(g.getFont().deriveFont(
1702 // AffineTransform.getScaleInstance(
1703 // width/g.getFontMetrics().stringWidth("Label"),
1704 // height/g.getFontMetrics().getHeight())));
1706 g.drawString(MessageManager.getString("label.label"), 0, 0);
1711 Color minCol = ColorUtils.getColor(gcol.getMinColour());
1713 g.fillRect(0, 0, s1, height);
1716 g.setColor(Color.white);
1717 g.fillRect(s1, 0, e1 - s1, height);
1719 g.setColor(ColorUtils.getColor(gcol.getMaxColour()));
1720 g.fillRect(0, e1, width - e1, height);
1725 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1730 FeatureColourI currentColor;
1732 FeatureColourChooser chooser;
1738 JColorChooser colorChooser;
1742 protected static final String EDIT = "edit";
1744 int selectedRow = 0;
1746 public ColorEditor(FeatureSettings me)
1749 // Set up the editor (from the table's point of view),
1750 // which is a button.
1751 // This button brings up the color chooser dialog,
1752 // which is the editor from the user's point of view.
1753 button = new JButton();
1754 button.setActionCommand(EDIT);
1755 button.addActionListener(this);
1756 button.setBorderPainted(false);
1757 // Set up the dialog that the button brings up.
1758 colorChooser = new JColorChooser();
1759 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1760 colorChooser, this, // OK button handler
1761 null); // no CANCEL button handler
1765 * Handles events from the editor button and from the dialog's OK button.
1768 public void actionPerformed(ActionEvent e)
1771 if (EDIT.equals(e.getActionCommand()))
1773 // The user has clicked the cell, so
1774 // bring up the dialog.
1775 if (currentColor.isSimpleColour())
1777 // bring up simple color chooser
1778 button.setBackground(ColorUtils.getColor(currentColor.getColour()));
1780 .setColor(ColorUtils.getColor(currentColor.getColour()));
1781 dialog.setVisible(true);
1785 // bring up graduated chooser.
1786 chooser = new FeatureColourChooser(me.fr, type);
1787 chooser.setRequestFocusEnabled(true);
1788 chooser.requestFocus();
1789 chooser.addActionListener(this);
1791 // Make the renderer reappear.
1792 fireEditingStopped();
1796 { // User pressed dialog's "OK" button.
1797 if (currentColor.isSimpleColour())
1799 currentColor = new FeatureColour(
1800 new Colour(colorChooser.getColor()));
1804 currentColor = chooser.getLastColour();
1806 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1807 fireEditingStopped();
1808 me.table.validate();
1812 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1814 public Object getCellEditorValue()
1816 return currentColor;
1819 // Implement the one method defined by TableCellEditor.
1821 public Component getTableCellEditorComponent(JTable table, Object value,
1822 boolean isSelected, int row, int column)
1824 currentColor = (FeatureColourI) value;
1825 this.selectedRow = row;
1826 type = me.table.getValueAt(row, 0).toString();
1827 button.setOpaque(true);
1828 button.setBackground(me.getBackground());
1829 if (!currentColor.isSimpleColour())
1831 JLabel btn = new JLabel();
1832 btn.setSize(button.getSize());
1833 FeatureSettings.renderGraduatedColor(btn, currentColor);
1834 button.setBackground(btn.getBackground());
1835 button.setIcon(btn.getIcon());
1836 button.setText(btn.getText());
1841 button.setIcon(null);
1842 button.setBackground(ColorUtils.getColor(currentColor.getColour()));