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 Cache.getProperty("LAST_DIRECTORY"), "fc",
753 "Sequence Feature Colours", "Sequence Feature Colours");
754 chooser.setFileView(new jalview.io.JalviewFileView());
755 chooser.setDialogTitle(MessageManager
756 .getString("label.load_feature_colours"));
757 chooser.setToolTipText(MessageManager.getString("action.load"));
759 int value = chooser.showOpenDialog(this);
761 if (value == JalviewFileChooser.APPROVE_OPTION)
763 File file = chooser.getSelectedFile();
767 InputStreamReader in = new InputStreamReader(new FileInputStream(
770 JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
772 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
775 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
778 Color mincol = null, maxcol = null;
781 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
782 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
784 } catch (Exception e)
786 Cache.log.warn("Couldn't parse out graduated feature color.",
789 FeatureColourI gcol = new FeatureColour(mincol, maxcol,
790 newcol.getMin(), newcol.getMax());
791 if (newcol.hasAutoScale())
793 gcol.setAutoScaled(newcol.getAutoScale());
795 if (newcol.hasColourByLabel())
797 gcol.setColourByLabel(newcol.getColourByLabel());
799 if (newcol.hasThreshold())
801 gcol.setThreshold(newcol.getThreshold());
803 if (newcol.getThreshType().length() > 0)
805 String ttyp = newcol.getThreshType();
806 if (ttyp.equalsIgnoreCase("ABOVE"))
808 gcol.setAboveThreshold(true);
810 if (ttyp.equalsIgnoreCase("BELOW"))
812 gcol.setBelowThreshold(true);
815 fr.setColour(name = newcol.getName(), gcol);
819 Color color = new Color(
820 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
821 fr.setColour(name = jucs.getColour(i).getName(),
822 new FeatureColour(color));
824 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
829 Object[][] data = ((FeatureTableModel) table.getModel())
832 updateFeatureRenderer(data, false);
835 } catch (Exception ex)
837 System.out.println("Error loading User Colour File\n" + ex);
844 JalviewFileChooser chooser = new JalviewFileChooser(
845 Cache.getProperty("LAST_DIRECTORY"), "fc",
846 "Sequence Feature Colours", "Sequence Feature Colours");
847 chooser.setFileView(new jalview.io.JalviewFileView());
848 chooser.setDialogTitle(MessageManager
849 .getString("label.save_feature_colours"));
850 chooser.setToolTipText(MessageManager.getString("action.save"));
852 int value = chooser.showSaveDialog(this);
854 if (value == JalviewFileChooser.APPROVE_OPTION)
856 String choice = chooser.getSelectedFile().getPath();
857 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
858 ucs.setSchemeName("Sequence Features");
861 PrintWriter out = new PrintWriter(new OutputStreamWriter(
862 new FileOutputStream(choice), "UTF-8"));
864 Set<String> fr_colours = fr.getAllFeatureColours();
865 Iterator<String> e = fr_colours.iterator();
866 float[] sortOrder = new float[fr_colours.size()];
867 String[] sortTypes = new String[fr_colours.size()];
871 sortTypes[i] = e.next();
872 sortOrder[i] = fr.getOrder(sortTypes[i]);
875 QuickSort.sort(sortOrder, sortTypes);
877 for (i = 0; i < sortTypes.length; i++)
879 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
880 col.setName(sortTypes[i]);
881 FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
882 if (fcol.isSimpleColour())
884 col.setRGB(Format.getHexString(fcol.getColour()));
888 col.setRGB(Format.getHexString(fcol.getMaxColour()));
889 col.setMin(fcol.getMin());
890 col.setMax(fcol.getMax());
891 col.setMinRGB(jalview.util.Format.getHexString(fcol
893 col.setAutoScale(fcol.isAutoScaled());
894 col.setThreshold(fcol.getThreshold());
895 col.setColourByLabel(fcol.isColourByLabel());
896 col.setThreshType(fcol.isAboveThreshold() ? "ABOVE" : (fcol
897 .isBelowThreshold() ? "BELOW" : "NONE"));
903 } catch (Exception ex)
905 ex.printStackTrace();
910 public void invertSelection()
912 for (int i = 0; i < table.getRowCount(); i++)
914 Boolean value = (Boolean) table.getValueAt(i, 2);
916 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
920 public void orderByAvWidth()
922 if (table == null || table.getModel() == null)
926 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
927 float[] width = new float[data.length];
931 for (int i = 0; i < data.length; i++)
933 awidth = typeWidth.get(data[i][0]);
936 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
937 // weight - but have to make per
938 // sequence, too (awidth[2])
939 // if (width[i]==1) // hack to distinguish single width sequences.
951 boolean sort = false;
952 for (int i = 0; i < width.length; i++)
954 // awidth = (float[]) typeWidth.get(data[i][0]);
957 width[i] = fr.getOrder(data[i][0].toString());
960 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
965 width[i] /= max; // normalize
966 fr.setOrder(data[i][0].toString(), width[i]); // store for later
970 sort = sort || width[i - 1] > width[i];
975 jalview.util.QuickSort.sort(width, data);
976 // update global priority order
979 updateFeatureRenderer(data, false);
987 frame.setClosed(true);
988 } catch (Exception exe)
994 public void updateFeatureRenderer(Object[][] data)
996 updateFeatureRenderer(data, true);
1000 * Update the priority order of features; only repaint if this changed the
1001 * order of visible features
1006 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
1008 if (fr.setFeaturePriority(data, visibleNew))
1010 af.alignPanel.paintAlignment(true);
1014 int selectedRow = -1;
1016 JTabbedPane tabbedPane = new JTabbedPane();
1018 BorderLayout borderLayout1 = new BorderLayout();
1020 BorderLayout borderLayout2 = new BorderLayout();
1022 BorderLayout borderLayout3 = new BorderLayout();
1024 JPanel bigPanel = new JPanel();
1026 BorderLayout borderLayout4 = new BorderLayout();
1028 JButton invert = new JButton();
1030 JPanel buttonPanel = new JPanel();
1032 JButton cancel = new JButton();
1034 JButton ok = new JButton();
1036 JButton loadColours = new JButton();
1038 JButton saveColours = new JButton();
1040 JPanel dasButtonPanel = new JPanel();
1042 JButton fetchDAS = new JButton();
1044 JButton saveDAS = new JButton();
1046 JButton cancelDAS = new JButton();
1048 JButton optimizeOrder = new JButton();
1050 JButton sortByScore = new JButton();
1052 JButton sortByDens = new JButton();
1054 JButton help = new JButton();
1056 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1058 private void jbInit() throws Exception
1060 this.setLayout(borderLayout1);
1061 settingsPane.setLayout(borderLayout2);
1062 dasSettingsPane.setLayout(borderLayout3);
1063 bigPanel.setLayout(borderLayout4);
1064 invert.setFont(JvSwingUtils.getLabelFont());
1065 invert.setText(MessageManager.getString("label.invert_selection"));
1066 invert.addActionListener(new ActionListener()
1069 public void actionPerformed(ActionEvent e)
1074 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1075 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1076 optimizeOrder.addActionListener(new ActionListener()
1079 public void actionPerformed(ActionEvent e)
1084 sortByScore.setFont(JvSwingUtils.getLabelFont());
1086 .setText(MessageManager.getString("label.seq_sort_by_score"));
1087 sortByScore.addActionListener(new ActionListener()
1090 public void actionPerformed(ActionEvent e)
1092 af.avc.sortAlignmentByFeatureScore(null);
1095 sortByDens.setFont(JvSwingUtils.getLabelFont());
1096 sortByDens.setText(MessageManager
1097 .getString("label.sequence_sort_by_density"));
1098 sortByDens.addActionListener(new ActionListener()
1101 public void actionPerformed(ActionEvent e)
1103 af.avc.sortAlignmentByFeatureDensity(null);
1106 help.setFont(JvSwingUtils.getLabelFont());
1107 help.setText(MessageManager.getString("action.help"));
1108 help.addActionListener(new ActionListener()
1111 public void actionPerformed(ActionEvent e)
1115 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1116 } catch (HelpSetException e1)
1118 e1.printStackTrace();
1122 help.setFont(JvSwingUtils.getLabelFont());
1123 help.setText(MessageManager.getString("action.help"));
1124 help.addActionListener(new ActionListener()
1127 public void actionPerformed(ActionEvent e)
1131 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1132 } catch (HelpSetException e1)
1134 e1.printStackTrace();
1138 cancel.setFont(JvSwingUtils.getLabelFont());
1139 cancel.setText(MessageManager.getString("action.cancel"));
1140 cancel.addActionListener(new ActionListener()
1143 public void actionPerformed(ActionEvent e)
1145 fr.setTransparency(originalTransparency);
1146 updateFeatureRenderer(originalData);
1150 ok.setFont(JvSwingUtils.getLabelFont());
1151 ok.setText(MessageManager.getString("action.ok"));
1152 ok.addActionListener(new ActionListener()
1155 public void actionPerformed(ActionEvent e)
1160 loadColours.setFont(JvSwingUtils.getLabelFont());
1161 loadColours.setText(MessageManager.getString("label.load_colours"));
1162 loadColours.addActionListener(new ActionListener()
1165 public void actionPerformed(ActionEvent e)
1170 saveColours.setFont(JvSwingUtils.getLabelFont());
1171 saveColours.setText(MessageManager.getString("label.save_colours"));
1172 saveColours.addActionListener(new ActionListener()
1175 public void actionPerformed(ActionEvent e)
1180 transparency.addChangeListener(new ChangeListener()
1183 public void stateChanged(ChangeEvent evt)
1185 fr.setTransparency((100 - transparency.getValue()) / 100f);
1186 af.alignPanel.paintAlignment(true);
1190 transparency.setMaximum(70);
1191 transparency.setToolTipText(MessageManager
1192 .getString("label.transparency_tip"));
1193 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1194 fetchDAS.addActionListener(new ActionListener()
1197 public void actionPerformed(ActionEvent e)
1199 fetchDAS_actionPerformed(e);
1202 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1203 saveDAS.addActionListener(new ActionListener()
1206 public void actionPerformed(ActionEvent e)
1208 saveDAS_actionPerformed(e);
1211 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1212 dasSettingsPane.setBorder(null);
1213 cancelDAS.setEnabled(false);
1214 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1215 cancelDAS.addActionListener(new ActionListener()
1218 public void actionPerformed(ActionEvent e)
1220 cancelDAS_actionPerformed(e);
1223 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1224 tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
1226 tabbedPane.addTab(MessageManager.getString("label.das_settings"),
1228 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1229 transbuttons.add(optimizeOrder);
1230 transbuttons.add(invert);
1231 transbuttons.add(sortByScore);
1232 transbuttons.add(sortByDens);
1233 transbuttons.add(help);
1234 JPanel sliderPanel = new JPanel();
1235 sliderPanel.add(transparency);
1236 transPanel.add(transparency);
1237 transPanel.add(transbuttons);
1238 buttonPanel.add(ok);
1239 buttonPanel.add(cancel);
1240 buttonPanel.add(loadColours);
1241 buttonPanel.add(saveColours);
1242 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1243 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1244 dasButtonPanel.add(fetchDAS);
1245 dasButtonPanel.add(cancelDAS);
1246 dasButtonPanel.add(saveDAS);
1247 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1248 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1251 public void fetchDAS_actionPerformed(ActionEvent e)
1253 fetchDAS.setEnabled(false);
1254 cancelDAS.setEnabled(true);
1255 dassourceBrowser.setGuiEnabled(false);
1256 Vector<jalviewSourceI> selectedSources = dassourceBrowser
1257 .getSelectedSources();
1258 doDasFeatureFetch(selectedSources, true, true);
1262 * get the features from selectedSources for all or the current selection
1264 * @param selectedSources
1265 * @param checkDbRefs
1266 * @param promptFetchDbRefs
1268 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1269 boolean checkDbRefs, boolean promptFetchDbRefs)
1271 SequenceI[] dataset, seqs;
1273 AlignmentViewport vp = af.getViewport();
1274 if (vp.getSelectionGroup() != null
1275 && vp.getSelectionGroup().getSize() > 0)
1277 iSize = vp.getSelectionGroup().getSize();
1278 dataset = new SequenceI[iSize];
1279 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1283 iSize = vp.getAlignment().getHeight();
1284 seqs = vp.getAlignment().getSequencesArray();
1287 dataset = new SequenceI[iSize];
1288 for (int i = 0; i < iSize; i++)
1290 dataset[i] = seqs[i].getDatasetSequence();
1293 cancelDAS.setEnabled(true);
1294 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1295 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1296 af.getViewport().setShowSequenceFeatures(true);
1297 af.showSeqFeatures.setSelected(true);
1301 * blocking call to initialise the das source browser
1303 public void initDasSources()
1305 dassourceBrowser.initDasSources();
1309 * examine the current list of das sources and return any matching the given
1310 * nicknames in sources
1313 * Vector of Strings to resolve to DAS source nicknames.
1314 * @return sources that are present in source list.
1316 public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
1318 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1322 * get currently selected das sources. ensure you have called initDasSources
1323 * before calling this.
1325 * @return vector of selected das source nicknames
1327 public Vector<jalviewSourceI> getSelectedSources()
1329 return dassourceBrowser.getSelectedSources();
1333 * properly initialise DAS fetcher and then initiate a new thread to fetch
1334 * features from the named sources (rather than any turned on by default)
1338 * if true then runs in same thread, otherwise passes to the Swing
1341 public void fetchDasFeatures(Vector<String> sources, boolean block)
1344 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1345 .resolveSourceNicknames(sources);
1346 if (resolved.size() == 0)
1348 resolved = dassourceBrowser.getSelectedSources();
1350 if (resolved.size() > 0)
1352 final List<jalviewSourceI> dassources = resolved;
1353 fetchDAS.setEnabled(false);
1354 // cancelDAS.setEnabled(true); doDasFetch does this.
1355 Runnable fetcher = new Runnable()
1361 doDasFeatureFetch(dassources, true, false);
1371 SwingUtilities.invokeLater(fetcher);
1376 public void saveDAS_actionPerformed(ActionEvent e)
1379 .saveProperties(jalview.bin.Cache.applicationProperties);
1382 public void complete()
1384 fetchDAS.setEnabled(true);
1385 cancelDAS.setEnabled(false);
1386 dassourceBrowser.setGuiEnabled(true);
1390 public void cancelDAS_actionPerformed(ActionEvent e)
1392 if (dasFeatureFetcher != null)
1394 dasFeatureFetcher.cancel();
1399 public void noDasSourceActive()
1403 .showInternalConfirmDialog(
1406 .getString("label.no_das_sources_selected_warn"),
1408 .getString("label.no_das_sources_selected_title"),
1409 JvOptionPane.DEFAULT_OPTION,
1410 JvOptionPane.INFORMATION_MESSAGE);
1413 // ///////////////////////////////////////////////////////////////////////
1414 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1415 // ///////////////////////////////////////////////////////////////////////
1416 class FeatureTableModel extends AbstractTableModel
1418 FeatureTableModel(Object[][] data)
1423 private String[] columnNames = {
1424 MessageManager.getString("label.feature_type"),
1425 MessageManager.getString("action.colour"),
1426 MessageManager.getString("label.display") };
1428 private Object[][] data;
1430 public Object[][] getData()
1435 public void setData(Object[][] data)
1441 public int getColumnCount()
1443 return columnNames.length;
1446 public Object[] getRow(int row)
1452 public int getRowCount()
1458 public String getColumnName(int col)
1460 return columnNames[col];
1464 public Object getValueAt(int row, int col)
1466 return data[row][col];
1470 public Class getColumnClass(int c)
1472 return getValueAt(0, c).getClass();
1476 public boolean isCellEditable(int row, int col)
1478 return col == 0 ? false : true;
1482 public void setValueAt(Object value, int row, int col)
1484 data[row][col] = value;
1485 fireTableCellUpdated(row, col);
1486 updateFeatureRenderer(data);
1491 class ColorRenderer extends JLabel implements TableCellRenderer
1493 javax.swing.border.Border unselectedBorder = null;
1495 javax.swing.border.Border selectedBorder = null;
1497 final String baseTT = "Click to edit, right/apple click for menu.";
1499 public ColorRenderer()
1501 setOpaque(true); // MUST do this for background to show up.
1502 setHorizontalTextPosition(SwingConstants.CENTER);
1503 setVerticalTextPosition(SwingConstants.CENTER);
1507 public Component getTableCellRendererComponent(JTable tbl,
1508 Object color, boolean isSelected, boolean hasFocus, int row,
1511 FeatureColourI cellColour = (FeatureColourI) color;
1512 // JLabel comp = new JLabel();
1516 // setBounds(getBounds());
1518 setToolTipText(baseTT);
1519 setBackground(tbl.getBackground());
1520 if (!cellColour.isSimpleColour())
1522 Rectangle cr = tbl.getCellRect(row, column, false);
1523 FeatureSettings.renderGraduatedColor(this, cellColour,
1524 (int) cr.getWidth(), (int) cr.getHeight());
1531 newColor = cellColour.getColour();
1532 setBackground(newColor);
1536 if (selectedBorder == null)
1538 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1539 tbl.getSelectionBackground());
1541 setBorder(selectedBorder);
1545 if (unselectedBorder == null)
1547 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1548 tbl.getBackground());
1550 setBorder(unselectedBorder);
1558 * update comp using rendering settings from gcol
1563 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol)
1565 int w = comp.getWidth(), h = comp.getHeight();
1568 w = (int) comp.getPreferredSize().getWidth();
1569 h = (int) comp.getPreferredSize().getHeight();
1576 renderGraduatedColor(comp, gcol, w, h);
1579 public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
1582 boolean thr = false;
1585 if (gcol.isAboveThreshold())
1589 tt += "Thresholded (Above " + gcol.getThreshold() + ") ";
1591 if (gcol.isBelowThreshold())
1595 tt += "Thresholded (Below " + gcol.getThreshold() + ") ";
1597 if (gcol.isColourByLabel())
1599 tt = "Coloured by label text. " + tt;
1609 Color newColor = gcol.getMaxColour();
1610 comp.setBackground(newColor);
1611 // System.err.println("Width is " + w / 2);
1612 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1613 comp.setIcon(ficon);
1614 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1615 // + newColor.getGreen() + ", " + newColor.getBlue()
1616 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1617 // + ", " + minCol.getBlue() + ")");
1619 comp.setHorizontalAlignment(SwingConstants.CENTER);
1621 if (tt.length() > 0)
1623 if (comp.getToolTipText() == null)
1625 comp.setToolTipText(tt);
1629 comp.setToolTipText(tt + " " + comp.getToolTipText());
1635 class FeatureIcon implements Icon
1637 FeatureColourI gcol;
1641 boolean midspace = false;
1643 int width = 50, height = 20;
1645 int s1, e1; // start and end of midpoint band for thresholded symbol
1647 Color mpcolour = Color.white;
1649 FeatureIcon(FeatureColourI gfc, Color bg, int w, int h, boolean mspace)
1669 public int getIconWidth()
1675 public int getIconHeight()
1681 public void paintIcon(Component c, Graphics g, int x, int y)
1684 if (gcol.isColourByLabel())
1687 g.fillRect(0, 0, width, height);
1688 // need an icon here.
1689 g.setColor(gcol.getMaxColour());
1691 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1693 // g.setFont(g.getFont().deriveFont(
1694 // AffineTransform.getScaleInstance(
1695 // width/g.getFontMetrics().stringWidth("Label"),
1696 // height/g.getFontMetrics().getHeight())));
1698 g.drawString(MessageManager.getString("label.label"), 0, 0);
1703 Color minCol = gcol.getMinColour();
1705 g.fillRect(0, 0, s1, height);
1708 g.setColor(Color.white);
1709 g.fillRect(s1, 0, e1 - s1, height);
1711 g.setColor(gcol.getMaxColour());
1712 g.fillRect(0, e1, width - e1, height);
1717 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1722 FeatureColourI currentColor;
1724 FeatureColourChooser chooser;
1730 JColorChooser colorChooser;
1734 protected static final String EDIT = "edit";
1736 int selectedRow = 0;
1738 public ColorEditor(FeatureSettings me)
1741 // Set up the editor (from the table's point of view),
1742 // which is a button.
1743 // This button brings up the color chooser dialog,
1744 // which is the editor from the user's point of view.
1745 button = new JButton();
1746 button.setActionCommand(EDIT);
1747 button.addActionListener(this);
1748 button.setBorderPainted(false);
1749 // Set up the dialog that the button brings up.
1750 colorChooser = new JColorChooser();
1751 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1752 colorChooser, this, // OK button handler
1753 null); // no CANCEL button handler
1757 * Handles events from the editor button and from the dialog's OK button.
1760 public void actionPerformed(ActionEvent e)
1763 if (EDIT.equals(e.getActionCommand()))
1765 // The user has clicked the cell, so
1766 // bring up the dialog.
1767 if (currentColor.isSimpleColour())
1769 // bring up simple color chooser
1770 button.setBackground(currentColor.getColour());
1771 colorChooser.setColor(currentColor.getColour());
1772 dialog.setVisible(true);
1776 // bring up graduated chooser.
1777 chooser = new FeatureColourChooser(me.fr, type);
1778 chooser.setRequestFocusEnabled(true);
1779 chooser.requestFocus();
1780 chooser.addActionListener(this);
1782 // Make the renderer reappear.
1783 fireEditingStopped();
1787 { // User pressed dialog's "OK" button.
1788 if (currentColor.isSimpleColour())
1790 currentColor = new FeatureColour(colorChooser.getColor());
1794 currentColor = chooser.getLastColour();
1796 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1797 fireEditingStopped();
1798 me.table.validate();
1802 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1804 public Object getCellEditorValue()
1806 return currentColor;
1809 // Implement the one method defined by TableCellEditor.
1811 public Component getTableCellEditorComponent(JTable table, Object value,
1812 boolean isSelected, int row, int column)
1814 currentColor = (FeatureColourI) value;
1815 this.selectedRow = row;
1816 type = me.table.getValueAt(row, 0).toString();
1817 button.setOpaque(true);
1818 button.setBackground(me.getBackground());
1819 if (!currentColor.isSimpleColour())
1821 JLabel btn = new JLabel();
1822 btn.setSize(button.getSize());
1823 FeatureSettings.renderGraduatedColor(btn, currentColor);
1824 button.setBackground(btn.getBackground());
1825 button.setIcon(btn.getIcon());
1826 button.setText(btn.getText());
1831 button.setIcon(null);
1832 button.setBackground(currentColor.getColour());