2 * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3 * Copyright (C) $$Year-Rel$$ The Jalview Authors
5 * This file is part of Jalview.
7 * Jalview is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation, either version 3
10 * of the License, or (at your option) any later version.
12 * Jalview is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Jalview. If not, see <http://www.gnu.org/licenses/>.
19 * The Jalview Authors are detailed in the 'AUTHORS' file.
23 import jalview.api.FeatureColourI;
24 import jalview.api.FeatureSettingsControllerI;
25 import jalview.bin.Cache;
26 import jalview.datamodel.SequenceFeature;
27 import jalview.datamodel.SequenceI;
28 import jalview.gui.Help.HelpId;
29 import jalview.io.JalviewFileChooser;
30 import jalview.io.JalviewFileView;
31 import jalview.schemabinding.version2.JalviewUserColours;
32 import jalview.schemes.FeatureColour;
33 import jalview.util.Format;
34 import jalview.util.MessageManager;
35 import jalview.util.Platform;
36 import jalview.util.QuickSort;
37 import jalview.viewmodel.AlignmentViewport;
38 import jalview.ws.dbsources.das.api.jalviewSourceI;
40 import java.awt.BorderLayout;
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Dimension;
45 import java.awt.Graphics;
46 import java.awt.GridLayout;
47 import java.awt.Rectangle;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
50 import java.awt.event.ItemEvent;
51 import java.awt.event.ItemListener;
52 import java.awt.event.MouseAdapter;
53 import java.awt.event.MouseEvent;
54 import java.awt.event.MouseMotionAdapter;
55 import java.beans.PropertyChangeEvent;
56 import java.beans.PropertyChangeListener;
58 import java.io.FileInputStream;
59 import java.io.FileOutputStream;
60 import java.io.InputStreamReader;
61 import java.io.OutputStreamWriter;
62 import java.io.PrintWriter;
63 import java.util.Arrays;
64 import java.util.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.JPanel;
85 import javax.swing.JPopupMenu;
86 import javax.swing.JScrollPane;
87 import javax.swing.JSlider;
88 import javax.swing.JTabbedPane;
89 import javax.swing.JTable;
90 import javax.swing.ListSelectionModel;
91 import javax.swing.SwingConstants;
92 import javax.swing.SwingUtilities;
93 import javax.swing.event.ChangeEvent;
94 import javax.swing.event.ChangeListener;
95 import javax.swing.table.AbstractTableModel;
96 import javax.swing.table.TableCellEditor;
97 import javax.swing.table.TableCellRenderer;
99 public class FeatureSettings extends JPanel implements
100 FeatureSettingsControllerI
102 DasSourceBrowser dassourceBrowser;
104 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
106 JPanel settingsPane = new JPanel();
108 JPanel dasSettingsPane = new JPanel();
110 final FeatureRenderer fr;
112 public final AlignFrame af;
114 Object[][] originalData;
116 private float originalTransparency;
118 final JInternalFrame frame;
120 JScrollPane scrollPane = new JScrollPane();
126 JSlider transparency = new JSlider();
128 JPanel transPanel = new JPanel(new GridLayout(1, 2));
130 private static final int MIN_WIDTH = 400;
132 private static final int MIN_HEIGHT = 400;
134 public FeatureSettings(AlignFrame af)
137 fr = af.getFeatureRenderer();
138 // allow transparency to be recovered
139 transparency.setMaximum(100 - (int) ((originalTransparency = fr
140 .getTransparency()) * 100));
145 } catch (Exception ex)
147 ex.printStackTrace();
153 public String getToolTipText(MouseEvent e)
155 if (table.columnAtPoint(e.getPoint()) == 0)
158 * Tooltip for feature name only
160 return JvSwingUtils.wrapTooltip(true, MessageManager
161 .getString("label.feature_settings_click_drag"));
166 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
167 table.setFont(new Font("Verdana", Font.PLAIN, 12));
168 table.setDefaultRenderer(Color.class, new ColorRenderer());
170 table.setDefaultEditor(Color.class, new ColorEditor(this));
172 table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
173 table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
174 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
176 table.addMouseListener(new MouseAdapter()
179 public void mousePressed(MouseEvent evt)
181 selectedRow = table.rowAtPoint(evt.getPoint());
182 if (evt.isPopupTrigger())
184 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
185 table.getValueAt(selectedRow, 1), fr.getMinMax(),
186 evt.getX(), evt.getY());
188 else if (evt.getClickCount() == 2)
190 boolean invertSelection = evt.isAltDown();
191 boolean toggleSelection = Platform.isControlDown(evt);
192 boolean extendSelection = evt.isShiftDown();
193 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
194 invertSelection, extendSelection, toggleSelection,
195 (String) table.getValueAt(selectedRow, 0));
199 // isPopupTrigger fires on mouseReleased on Windows
201 public void mouseReleased(MouseEvent evt)
203 selectedRow = table.rowAtPoint(evt.getPoint());
204 if (evt.isPopupTrigger())
206 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
207 table.getValueAt(selectedRow, 1), fr.getMinMax(),
208 evt.getX(), evt.getY());
213 table.addMouseMotionListener(new MouseMotionAdapter()
216 public void mouseDragged(MouseEvent evt)
218 int newRow = table.rowAtPoint(evt.getPoint());
219 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
222 * reposition 'selectedRow' to 'newRow' (the dragged to location)
223 * this could be more than one row away for a very fast drag action
224 * so just swap it with adjacent rows until we get it there
226 Object[][] data = ((FeatureTableModel) table.getModel())
228 int direction = newRow < selectedRow ? -1 : 1;
229 for (int i = selectedRow; i != newRow; i += direction)
231 Object[] temp = data[i];
232 data[i] = data[i + direction];
233 data[i + direction] = temp;
235 updateFeatureRenderer(data);
237 selectedRow = newRow;
241 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
242 // MessageManager.getString("label.feature_settings_click_drag")));
243 scrollPane.setViewportView(table);
245 dassourceBrowser = new DasSourceBrowser(this);
246 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
248 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
250 fr.findAllFeatures(true); // display everything!
253 discoverAllFeatureData();
254 final PropertyChangeListener change;
255 final FeatureSettings fs = this;
256 fr.addPropertyChangeListener(change = new PropertyChangeListener()
259 public void propertyChange(PropertyChangeEvent evt)
261 if (!fs.resettingTable && !fs.handlingUpdate)
263 fs.handlingUpdate = true;
264 fs.resetTable(null); // new groups may be added with new seuqence
265 // feature types only
266 fs.handlingUpdate = false;
272 frame = new JInternalFrame();
273 frame.setContentPane(this);
274 if (Platform.isAMac())
276 Desktop.addInternalFrame(frame,
277 MessageManager.getString("label.sequence_feature_settings"),
282 Desktop.addInternalFrame(frame,
283 MessageManager.getString("label.sequence_feature_settings"),
286 frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
288 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
291 public void internalFrameClosed(
292 javax.swing.event.InternalFrameEvent evt)
294 fr.removePropertyChangeListener(change);
295 dassourceBrowser.fs = null;
298 frame.setLayer(JLayeredPane.PALETTE_LAYER);
301 protected void popupSort(final int selectedRow, final String type,
302 final Object typeCol, final Map<String, float[][]> minmax, int x,
305 final FeatureColourI featureColour = (FeatureColourI) typeCol;
307 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
308 "label.settings_for_param", new String[] { type }));
309 JMenuItem scr = new JMenuItem(
310 MessageManager.getString("label.sort_by_score"));
312 final FeatureSettings me = this;
313 scr.addActionListener(new ActionListener()
317 public void actionPerformed(ActionEvent e)
319 me.af.avc.sortAlignmentByFeatureScore(Arrays
320 .asList(new String[] { type }));
324 JMenuItem dens = new JMenuItem(
325 MessageManager.getString("label.sort_by_density"));
326 dens.addActionListener(new ActionListener()
330 public void actionPerformed(ActionEvent e)
332 me.af.avc.sortAlignmentByFeatureDensity(Arrays
333 .asList(new String[] { type }));
340 final float[][] typeMinMax = minmax.get(type);
342 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
343 * this is broken at the moment and isn't that useful anyway!
344 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
347 * public void actionPerformed(ActionEvent e) {
348 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
349 * null); } else { minmax.put(type, typeMinMax); } }
355 if (typeMinMax != null && typeMinMax[0] != null)
357 // if (table.getValueAt(row, column));
358 // graduated colourschemes for those where minmax exists for the
359 // positional features
360 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
362 mxcol.setSelected(!featureColour.isSimpleColour());
364 mxcol.addActionListener(new ActionListener()
366 JColorChooser colorChooser;
369 public void actionPerformed(ActionEvent e)
371 if (e.getSource() == mxcol)
373 if (featureColour.isSimpleColour())
375 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
377 fc.addActionListener(this);
381 // bring up simple color chooser
382 colorChooser = new JColorChooser();
383 JDialog dialog = JColorChooser.createDialog(me,
384 "Select new Colour", true, // modal
385 colorChooser, this, // OK button handler
386 null); // no CANCEL button handler
387 colorChooser.setColor(featureColour.getMaxColour());
388 dialog.setVisible(true);
393 if (e.getSource() instanceof FeatureColourChooser)
395 FeatureColourChooser fc = (FeatureColourChooser) e
397 table.setValueAt(fc.getLastColour(), selectedRow, 1);
402 // probably the color chooser!
404 new FeatureColour(colorChooser.getColor()),
407 me.updateFeatureRenderer(
408 ((FeatureTableModel) table.getModel()).getData(),
417 JMenuItem selCols = new JMenuItem(
418 MessageManager.getString("label.select_columns_containing"));
419 selCols.addActionListener(new ActionListener()
422 public void actionPerformed(ActionEvent arg0)
424 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
428 JMenuItem clearCols = new JMenuItem(
429 MessageManager.getString("label.select_columns_not_containing"));
430 clearCols.addActionListener(new ActionListener()
433 public void actionPerformed(ActionEvent arg0)
435 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
439 JMenuItem hideCols = new JMenuItem(
440 MessageManager.getString("label.hide_columns_containing"));
441 hideCols.addActionListener(new ActionListener()
444 public void actionPerformed(ActionEvent arg0)
446 fr.ap.alignFrame.hideFeatureColumns(type, true);
449 JMenuItem hideOtherCols = new JMenuItem(
450 MessageManager.getString("label.hide_columns_not_containing"));
451 hideOtherCols.addActionListener(new ActionListener()
454 public void actionPerformed(ActionEvent arg0)
456 fr.ap.alignFrame.hideFeatureColumns(type, false);
462 men.add(hideOtherCols);
463 men.show(table, x, y);
467 * true when Feature Settings are updating from feature renderer
469 private boolean handlingUpdate = false;
472 * contains a float[3] for each feature type string. created by setTableData
474 Map<String, float[]> typeWidth = null;
477 synchronized public void discoverAllFeatureData()
479 Vector<String> allFeatures = new Vector<String>();
480 Vector<String> allGroups = new Vector<String>();
481 SequenceFeature[] tmpfeatures;
483 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
485 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
486 .getSequenceFeatures();
487 if (tmpfeatures == null)
493 while (index < tmpfeatures.length)
495 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
501 if (tmpfeatures[index].getFeatureGroup() != null)
503 group = tmpfeatures[index].featureGroup;
504 if (!allGroups.contains(group))
506 allGroups.addElement(group);
507 checkGroupState(group);
511 if (!allFeatures.contains(tmpfeatures[index].getType()))
513 allFeatures.addElement(tmpfeatures[index].getType());
525 * Synchronise gui group list and check visibility of group
528 * @return true if group is visible
530 private boolean checkGroupState(String group)
532 boolean visible = fr.checkGroupVisibility(group, true);
534 if (groupPanel == null)
536 groupPanel = new JPanel();
539 boolean alreadyAdded = false;
540 for (int g = 0; g < groupPanel.getComponentCount(); g++)
542 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
545 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
555 final String grp = group;
556 final JCheckBox check = new JCheckBox(group, visible);
557 check.setFont(new Font("Serif", Font.BOLD, 12));
558 check.addItemListener(new ItemListener()
561 public void itemStateChanged(ItemEvent evt)
563 fr.setGroupVisibility(check.getText(), check.isSelected());
564 af.alignPanel.getSeqPanel().seqCanvas.repaint();
565 if (af.alignPanel.overviewPanel != null)
567 af.alignPanel.overviewPanel.updateOverviewImage();
570 resetTable(new String[] { grp });
573 groupPanel.add(check);
577 boolean resettingTable = false;
579 synchronized void resetTable(String[] groupChanged)
581 if (resettingTable == true)
585 resettingTable = true;
586 typeWidth = new Hashtable<String, float[]>();
587 // TODO: change avWidth calculation to 'per-sequence' average and use long
589 float[] avWidth = null;
590 SequenceFeature[] tmpfeatures;
591 String group = null, type;
592 Vector<String> visibleChecks = new Vector<String>();
594 // Find out which features should be visible depending on which groups
595 // are selected / deselected
596 // and recompute average width ordering
597 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
600 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
601 .getSequenceFeatures();
602 if (tmpfeatures == null)
608 while (index < tmpfeatures.length)
610 group = tmpfeatures[index].featureGroup;
612 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
618 if (group == null || checkGroupState(group))
620 type = tmpfeatures[index].getType();
621 if (!visibleChecks.contains(type))
623 visibleChecks.addElement(type);
626 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
628 typeWidth.put(tmpfeatures[index].getType(),
629 avWidth = new float[3]);
633 avWidth = typeWidth.get(tmpfeatures[index].getType());
636 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
638 avWidth[1] += 1 + tmpfeatures[index].getBegin()
639 - tmpfeatures[index].getEnd();
643 avWidth[1] += 1 + tmpfeatures[index].getEnd()
644 - tmpfeatures[index].getBegin();
650 int fSize = visibleChecks.size();
651 Object[][] data = new Object[fSize][3];
654 if (fr.hasRenderOrder())
658 fr.findAllFeatures(groupChanged != null); // prod to update
659 // colourschemes. but don't
661 // First add the checks in the previous render order,
662 // in case the window has been closed and reopened
664 List<String> frl = fr.getRenderOrder();
665 for (int ro = frl.size() - 1; ro > -1; ro--)
669 if (!visibleChecks.contains(type))
674 data[dataIndex][0] = type;
675 data[dataIndex][1] = fr.getFeatureStyle(type);
676 data[dataIndex][2] = new Boolean(af.getViewport()
677 .getFeaturesDisplayed().isVisible(type));
679 visibleChecks.removeElement(type);
683 fSize = visibleChecks.size();
684 for (int i = 0; i < fSize; i++)
686 // These must be extra features belonging to the group
687 // which was just selected
688 type = visibleChecks.elementAt(i).toString();
689 data[dataIndex][0] = type;
691 data[dataIndex][1] = fr.getFeatureStyle(type);
692 if (data[dataIndex][1] == null)
694 // "Colour has been updated in another view!!"
695 fr.clearRenderOrder();
699 data[dataIndex][2] = new Boolean(true);
703 if (originalData == null)
705 originalData = new Object[data.length][3];
706 for (int i = 0; i < data.length; i++)
708 System.arraycopy(data[i], 0, originalData[i], 0, 3);
712 table.setModel(new FeatureTableModel(data));
713 table.getColumnModel().getColumn(0).setPreferredWidth(200);
715 if (groupPanel != null)
717 groupPanel.setLayout(new GridLayout(
718 fr.getFeatureGroupsSize() / 4 + 1, 4));
720 groupPanel.validate();
721 bigPanel.add(groupPanel, BorderLayout.NORTH);
724 updateFeatureRenderer(data, groupChanged != null);
725 resettingTable = false;
729 * reorder data based on the featureRenderers global priority list.
733 private void ensureOrder(Object[][] data)
735 boolean sort = false;
736 float[] order = new float[data.length];
737 for (int i = 0; i < order.length; i++)
739 order[i] = fr.getOrder(data[i][0].toString());
742 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
746 sort = sort || order[i - 1] > order[i];
751 jalview.util.QuickSort.sort(order, data);
757 JalviewFileChooser chooser = new JalviewFileChooser("fc",
758 "Sequence Feature Colours");
759 chooser.setFileView(new 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(mincol, maxcol,
795 newcol.getMin(), newcol.getMax());
796 if (newcol.hasAutoScale())
798 gcol.setAutoScaled(newcol.getAutoScale());
800 if (newcol.hasColourByLabel())
802 gcol.setColourByLabel(newcol.getColourByLabel());
804 if (newcol.hasThreshold())
806 gcol.setThreshold(newcol.getThreshold());
808 if (newcol.getThreshType().length() > 0)
810 String ttyp = newcol.getThreshType();
811 if (ttyp.equalsIgnoreCase("ABOVE"))
813 gcol.setAboveThreshold(true);
815 if (ttyp.equalsIgnoreCase("BELOW"))
817 gcol.setBelowThreshold(true);
820 fr.setColour(name = newcol.getName(), gcol);
824 Color color = new Color(
825 Integer.parseInt(jucs.getColour(i).getRGB(), 16));
826 fr.setColour(name = jucs.getColour(i).getName(),
827 new FeatureColour(color));
829 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
834 Object[][] data = ((FeatureTableModel) table.getModel())
837 updateFeatureRenderer(data, false);
840 } catch (Exception ex)
842 System.out.println("Error loading User Colour File\n" + ex);
849 JalviewFileChooser chooser = new JalviewFileChooser("fc",
850 "Sequence Feature Colours");
851 chooser.setFileView(new 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 JvOptionPane.DEFAULT_OPTION,
1414 JvOptionPane.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());