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.bin.Cache;
24 import jalview.datamodel.SequenceFeature;
25 import jalview.datamodel.SequenceI;
26 import jalview.gui.Help.HelpId;
27 import jalview.io.JalviewFileChooser;
28 import jalview.schemes.AnnotationColourGradient;
29 import jalview.schemes.GraduatedColor;
30 import jalview.util.MessageManager;
31 import jalview.viewmodel.AlignmentViewport;
32 import jalview.ws.dbsources.das.api.jalviewSourceI;
34 import java.awt.BorderLayout;
35 import java.awt.Color;
36 import java.awt.Component;
38 import java.awt.Graphics;
39 import java.awt.GridLayout;
40 import java.awt.Rectangle;
41 import java.awt.event.ActionEvent;
42 import java.awt.event.ActionListener;
43 import java.awt.event.ItemEvent;
44 import java.awt.event.ItemListener;
45 import java.awt.event.MouseAdapter;
46 import java.awt.event.MouseEvent;
47 import java.awt.event.MouseMotionAdapter;
48 import java.beans.PropertyChangeEvent;
49 import java.beans.PropertyChangeListener;
51 import java.io.FileInputStream;
52 import java.io.FileOutputStream;
53 import java.io.InputStreamReader;
54 import java.io.OutputStreamWriter;
55 import java.io.PrintWriter;
56 import java.util.Hashtable;
57 import java.util.Iterator;
58 import java.util.List;
60 import java.util.Vector;
62 import javax.help.HelpSetException;
63 import javax.swing.AbstractCellEditor;
64 import javax.swing.BorderFactory;
65 import javax.swing.Icon;
66 import javax.swing.JButton;
67 import javax.swing.JCheckBox;
68 import javax.swing.JCheckBoxMenuItem;
69 import javax.swing.JColorChooser;
70 import javax.swing.JDialog;
71 import javax.swing.JInternalFrame;
72 import javax.swing.JLabel;
73 import javax.swing.JLayeredPane;
74 import javax.swing.JMenuItem;
75 import javax.swing.JOptionPane;
76 import javax.swing.JPanel;
77 import javax.swing.JPopupMenu;
78 import javax.swing.JScrollPane;
79 import javax.swing.JSlider;
80 import javax.swing.JTabbedPane;
81 import javax.swing.JTable;
82 import javax.swing.ListSelectionModel;
83 import javax.swing.SwingConstants;
84 import javax.swing.SwingUtilities;
85 import javax.swing.event.ChangeEvent;
86 import javax.swing.event.ChangeListener;
87 import javax.swing.table.AbstractTableModel;
88 import javax.swing.table.TableCellEditor;
89 import javax.swing.table.TableCellRenderer;
91 public class FeatureSettings extends JPanel
93 DasSourceBrowser dassourceBrowser;
95 jalview.ws.DasSequenceFeatureFetcher dasFeatureFetcher;
97 JPanel settingsPane = new JPanel();
99 JPanel dasSettingsPane = new JPanel();
101 final FeatureRenderer fr;
103 public final AlignFrame af;
105 Object[][] originalData;
107 private float originalTransparency;
109 final JInternalFrame frame;
111 JScrollPane scrollPane = new JScrollPane();
117 JSlider transparency = new JSlider();
119 JPanel transPanel = new JPanel(new GridLayout(1, 2));
121 public FeatureSettings(AlignFrame af)
124 fr = af.getFeatureRenderer();
125 // allow transparency to be recovered
126 transparency.setMaximum(100 - (int) ((originalTransparency=fr.getTransparency()) * 100));
131 } catch (Exception ex)
133 ex.printStackTrace();
136 table = new JTable() {
138 public String getToolTipText(MouseEvent e) {
139 if (table.columnAtPoint(e.getPoint()) == 0) {
141 * Tooltip for feature name only
143 return JvSwingUtils.wrapTooltip(true,
144 MessageManager.getString("label.feature_settings_click_drag"));
149 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
150 table.setFont(new Font("Verdana", Font.PLAIN, 12));
151 table.setDefaultRenderer(Color.class, new ColorRenderer());
153 table.setDefaultEditor(Color.class, new ColorEditor(this));
155 table.setDefaultEditor(GraduatedColor.class, new ColorEditor(this));
156 table.setDefaultRenderer(GraduatedColor.class, new ColorRenderer());
157 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
159 table.addMouseListener(new MouseAdapter()
161 public void mousePressed(MouseEvent evt)
163 selectedRow = table.rowAtPoint(evt.getPoint());
164 if (SwingUtilities.isRightMouseButton(evt))
166 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
167 table.getValueAt(selectedRow, 1), fr.getMinMax(),
168 evt.getX(), evt.getY());
170 else if (evt.getClickCount() == 2)
172 fr.ap.alignFrame.avc.markColumnsContainingFeatures(
173 evt.isAltDown(), evt.isShiftDown() || evt.isMetaDown(),
175 (String) table.getValueAt(selectedRow, 0));
179 // isPopupTrigger fires on mouseReleased on Mac
181 public void mouseReleased(MouseEvent evt)
183 selectedRow = table.rowAtPoint(evt.getPoint());
184 if (evt.isPopupTrigger())
186 popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
187 table.getValueAt(selectedRow, 1), fr.getMinMax(),
194 table.addMouseMotionListener(new MouseMotionAdapter()
196 public void mouseDragged(MouseEvent evt)
198 int newRow = table.rowAtPoint(evt.getPoint());
199 if (newRow != selectedRow && selectedRow != -1 && newRow != -1)
201 Object[] temp = new Object[3];
202 temp[0] = table.getValueAt(selectedRow, 0);
203 temp[1] = table.getValueAt(selectedRow, 1);
204 temp[2] = table.getValueAt(selectedRow, 2);
206 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
207 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
208 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
210 table.setValueAt(temp[0], newRow, 0);
211 table.setValueAt(temp[1], newRow, 1);
212 table.setValueAt(temp[2], newRow, 2);
214 selectedRow = newRow;
218 // table.setToolTipText(JvSwingUtils.wrapTooltip(true,
219 // MessageManager.getString("label.feature_settings_click_drag")));
220 scrollPane.setViewportView(table);
222 dassourceBrowser = new DasSourceBrowser(this);
223 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
225 if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
227 fr.findAllFeatures(true); // display everything!
231 final PropertyChangeListener change;
232 final FeatureSettings fs = this;
233 fr.addPropertyChangeListener(change = new PropertyChangeListener()
235 public void propertyChange(PropertyChangeEvent evt)
237 if (!fs.resettingTable && !fs.handlingUpdate)
239 fs.handlingUpdate = true;
240 fs.resetTable(null); // new groups may be added with new seuqence
241 // feature types only
242 fs.handlingUpdate = false;
248 frame = new JInternalFrame();
249 frame.setContentPane(this);
250 if (new jalview.util.Platform().isAMac())
252 Desktop.addInternalFrame(frame,
253 MessageManager.getString("label.sequence_feature_settings"),
258 Desktop.addInternalFrame(frame,
259 MessageManager.getString("label.sequence_feature_settings"),
263 frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
265 public void internalFrameClosed(
266 javax.swing.event.InternalFrameEvent evt)
268 fr.removePropertyChangeListener(change);
269 dassourceBrowser.fs = null;
272 frame.setLayer(JLayeredPane.PALETTE_LAYER);
275 protected void popupSort(final int selectedRow, final String type,
276 final Object typeCol, final Hashtable minmax, int x, int y)
278 JPopupMenu men = new JPopupMenu(MessageManager.formatMessage(
279 "label.settings_for_param", new String[]
281 JMenuItem scr = new JMenuItem(
282 MessageManager.getString("label.sort_by_score"));
284 final FeatureSettings me = this;
285 scr.addActionListener(new ActionListener()
288 public void actionPerformed(ActionEvent e)
290 me.af.avc.sortAlignmentByFeatureScore(new String[]
295 JMenuItem dens = new JMenuItem(
296 MessageManager.getString("label.sort_by_density"));
297 dens.addActionListener(new ActionListener()
300 public void actionPerformed(ActionEvent e)
302 me.af.avc.sortAlignmentByFeatureDensity(new String[]
310 final Object typeMinMax = minmax.get(type);
312 * final JCheckBoxMenuItem chb = new JCheckBoxMenuItem("Vary Height"); //
313 * this is broken at the moment and isn't that useful anyway!
314 * chb.setSelected(minmax.get(type) != null); chb.addActionListener(new
317 * public void actionPerformed(ActionEvent e) {
318 * chb.setState(chb.getState()); if (chb.getState()) { minmax.put(type,
319 * null); } else { minmax.put(type, typeMinMax); } }
325 if (typeMinMax != null && ((float[][]) typeMinMax)[0] != null)
327 // if (table.getValueAt(row, column));
328 // graduated colourschemes for those where minmax exists for the
329 // positional features
330 final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
332 mxcol.setSelected(!(typeCol instanceof Color));
334 mxcol.addActionListener(new ActionListener()
336 JColorChooser colorChooser;
338 public void actionPerformed(ActionEvent e)
340 if (e.getSource() == mxcol)
342 if (typeCol instanceof Color)
344 FeatureColourChooser fc = new FeatureColourChooser(me.fr,
346 fc.addActionListener(this);
350 // bring up simple color chooser
351 colorChooser = new JColorChooser();
352 JDialog dialog = JColorChooser.createDialog(me,
353 "Select new Colour", true, // modal
354 colorChooser, this, // OK button handler
355 null); // no CANCEL button handler
356 colorChooser.setColor(((GraduatedColor) typeCol)
358 dialog.setVisible(true);
363 if (e.getSource() instanceof FeatureColourChooser)
365 FeatureColourChooser fc = (FeatureColourChooser) e
367 table.setValueAt(fc.getLastColour(), selectedRow, 1);
372 // probably the color chooser!
373 table.setValueAt(colorChooser.getColor(), selectedRow, 1);
375 me.updateFeatureRenderer(
376 ((FeatureTableModel) table.getModel()).getData(),
385 JMenuItem selCols = new JMenuItem(
386 MessageManager.getString("label.select_columns_containing"));
387 selCols.addActionListener(new ActionListener()
391 public void actionPerformed(ActionEvent arg0)
393 fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
397 JMenuItem clearCols = new JMenuItem(
398 MessageManager.getString("label.select_columns_not_containing"));
399 clearCols.addActionListener(new ActionListener()
403 public void actionPerformed(ActionEvent arg0)
405 fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
411 men.show(table, x, y);
415 * true when Feature Settings are updating from feature renderer
417 private boolean handlingUpdate = false;
420 * contains a float[3] for each feature type string. created by setTableData
422 Hashtable typeWidth = null;
424 synchronized public void setTableData()
426 Vector allFeatures = new Vector();
427 Vector allGroups = new Vector();
428 SequenceFeature[] tmpfeatures;
430 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
432 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
433 .getSequenceFeatures();
434 if (tmpfeatures == null)
440 while (index < tmpfeatures.length)
442 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
448 if (tmpfeatures[index].getFeatureGroup() != null)
450 group = tmpfeatures[index].featureGroup;
451 if (!allGroups.contains(group))
453 allGroups.addElement(group);
454 checkGroupState(group);
458 if (!allFeatures.contains(tmpfeatures[index].getType()))
460 allFeatures.addElement(tmpfeatures[index].getType());
472 * Synchronise gui group list and check visibility of group
475 * @return true if group is visible
477 private boolean checkGroupState(String group)
479 boolean visible = fr.checkGroupVisibility(group, true);
481 if (groupPanel == null)
483 groupPanel = new JPanel();
486 boolean alreadyAdded = false;
487 for (int g = 0; g < groupPanel.getComponentCount(); g++)
489 if (((JCheckBox) groupPanel.getComponent(g)).getText().equals(group))
492 ((JCheckBox) groupPanel.getComponent(g)).setSelected(visible);
502 final String grp = group;
503 final JCheckBox check = new JCheckBox(group, visible);
504 check.setFont(new Font("Serif", Font.BOLD, 12));
505 check.addItemListener(new ItemListener()
507 public void itemStateChanged(ItemEvent evt)
509 fr.setGroupVisibility(check.getText(), check.isSelected());
510 af.alignPanel.getSeqPanel().seqCanvas.repaint();
511 if (af.alignPanel.overviewPanel != null)
513 af.alignPanel.overviewPanel.updateOverviewImage();
516 resetTable(new String[]
520 groupPanel.add(check);
524 boolean resettingTable = false;
526 synchronized void resetTable(String[] groupChanged)
528 if (resettingTable == true)
532 resettingTable = true;
533 typeWidth = new Hashtable();
534 // TODO: change avWidth calculation to 'per-sequence' average and use long
536 float[] avWidth = null;
537 SequenceFeature[] tmpfeatures;
538 String group = null, type;
539 Vector visibleChecks = new Vector();
541 // Find out which features should be visible depending on which groups
542 // are selected / deselected
543 // and recompute average width ordering
544 for (int i = 0; i < af.getViewport().getAlignment().getHeight(); i++)
547 tmpfeatures = af.getViewport().getAlignment().getSequenceAt(i)
548 .getSequenceFeatures();
549 if (tmpfeatures == null)
555 while (index < tmpfeatures.length)
557 group = tmpfeatures[index].featureGroup;
559 if (tmpfeatures[index].begin == 0 && tmpfeatures[index].end == 0)
565 if (group == null || checkGroupState(group))
567 type = tmpfeatures[index].getType();
568 if (!visibleChecks.contains(type))
570 visibleChecks.addElement(type);
573 if (!typeWidth.containsKey(tmpfeatures[index].getType()))
575 typeWidth.put(tmpfeatures[index].getType(),
576 avWidth = new float[3]);
580 avWidth = (float[]) typeWidth.get(tmpfeatures[index].getType());
583 if (tmpfeatures[index].getBegin() > tmpfeatures[index].getEnd())
585 avWidth[1] += 1 + tmpfeatures[index].getBegin()
586 - tmpfeatures[index].getEnd();
590 avWidth[1] += 1 + tmpfeatures[index].getEnd()
591 - tmpfeatures[index].getBegin();
597 int fSize = visibleChecks.size();
598 Object[][] data = new Object[fSize][3];
601 if (fr.hasRenderOrder())
605 fr.findAllFeatures(groupChanged != null); // prod to update
606 // colourschemes. but don't
608 // First add the checks in the previous render order,
609 // in case the window has been closed and reopened
611 List<String> frl = fr.getRenderOrder();
612 for (int ro = frl.size() - 1; ro > -1; ro--)
616 if (!visibleChecks.contains(type))
621 data[dataIndex][0] = type;
622 data[dataIndex][1] = fr.getFeatureStyle(type);
623 data[dataIndex][2] = new Boolean(af.getViewport()
624 .getFeaturesDisplayed().isVisible(type));
626 visibleChecks.removeElement(type);
630 fSize = visibleChecks.size();
631 for (int i = 0; i < fSize; i++)
633 // These must be extra features belonging to the group
634 // which was just selected
635 type = visibleChecks.elementAt(i).toString();
636 data[dataIndex][0] = type;
638 data[dataIndex][1] = fr.getFeatureStyle(type);
639 if (data[dataIndex][1] == null)
641 // "Colour has been updated in another view!!"
642 fr.clearRenderOrder();
646 data[dataIndex][2] = new Boolean(true);
650 if (originalData == null)
652 originalData = new Object[data.length][3];
653 for (int i = 0; i < data.length; i++)
655 System.arraycopy(data[i], 0, originalData[i], 0, 3);
659 table.setModel(new FeatureTableModel(data));
660 table.getColumnModel().getColumn(0).setPreferredWidth(200);
662 if (groupPanel != null)
664 groupPanel.setLayout(new GridLayout(
665 fr.getFeatureGroupsSize() / 4 + 1, 4));
667 groupPanel.validate();
668 bigPanel.add(groupPanel, BorderLayout.NORTH);
671 updateFeatureRenderer(data, groupChanged != null);
672 resettingTable = false;
676 * reorder data based on the featureRenderers global priority list.
680 private void ensureOrder(Object[][] data)
682 boolean sort = false;
683 float[] order = new float[data.length];
684 for (int i = 0; i < order.length; i++)
686 order[i] = fr.getOrder(data[i][0].toString());
689 order[i] = fr.setOrder(data[i][0].toString(), i / order.length);
693 sort = sort || order[i - 1] > order[i];
698 jalview.util.QuickSort.sort(order, data);
704 JalviewFileChooser chooser = new JalviewFileChooser(
705 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
706 { "fc" }, new String[]
707 { "Sequence Feature Colours" }, "Sequence Feature Colours");
708 chooser.setFileView(new jalview.io.JalviewFileView());
709 chooser.setDialogTitle(MessageManager.getString("label.load_feature_colours"));
710 chooser.setToolTipText(MessageManager.getString("action.load"));
712 int value = chooser.showOpenDialog(this);
714 if (value == JalviewFileChooser.APPROVE_OPTION)
716 File file = chooser.getSelectedFile();
720 InputStreamReader in = new InputStreamReader(new FileInputStream(
723 jalview.schemabinding.version2.JalviewUserColours jucs = new jalview.schemabinding.version2.JalviewUserColours();
727 for (int i = jucs.getColourCount() - 1; i >= 0; i--)
730 jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
733 Color mincol = null, maxcol = null;
736 mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
737 maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
739 } catch (Exception e)
741 Cache.log.warn("Couldn't parse out graduated feature color.",
744 GraduatedColor gcol = new GraduatedColor(mincol, maxcol,
745 newcol.getMin(), newcol.getMax());
746 if (newcol.hasAutoScale())
748 gcol.setAutoScaled(newcol.getAutoScale());
750 if (newcol.hasColourByLabel())
752 gcol.setColourByLabel(newcol.getColourByLabel());
754 if (newcol.hasThreshold())
756 gcol.setThresh(newcol.getThreshold());
757 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD); // default
759 if (newcol.getThreshType().length() > 0)
761 String ttyp = newcol.getThreshType();
762 if (ttyp.equalsIgnoreCase("NONE"))
764 gcol.setThreshType(AnnotationColourGradient.NO_THRESHOLD);
766 if (ttyp.equalsIgnoreCase("ABOVE"))
768 gcol.setThreshType(AnnotationColourGradient.ABOVE_THRESHOLD);
770 if (ttyp.equalsIgnoreCase("BELOW"))
772 gcol.setThreshType(AnnotationColourGradient.BELOW_THRESHOLD);
775 fr.setColour(name = newcol.getName(), gcol);
779 fr.setColour(name = jucs.getColour(i).getName(), new Color(
780 Integer.parseInt(jucs.getColour(i).getRGB(), 16)));
782 fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
787 Object[][] data = ((FeatureTableModel) table.getModel())
790 updateFeatureRenderer(data, false);
793 } catch (Exception ex)
795 System.out.println("Error loading User Colour File\n" + ex);
802 JalviewFileChooser chooser = new JalviewFileChooser(
803 jalview.bin.Cache.getProperty("LAST_DIRECTORY"), new String[]
804 { "fc" }, new String[]
805 { "Sequence Feature Colours" }, "Sequence Feature Colours");
806 chooser.setFileView(new jalview.io.JalviewFileView());
807 chooser.setDialogTitle(MessageManager.getString("label.save_feature_colours"));
808 chooser.setToolTipText(MessageManager.getString("action.save"));
810 int value = chooser.showSaveDialog(this);
812 if (value == JalviewFileChooser.APPROVE_OPTION)
814 String choice = chooser.getSelectedFile().getPath();
815 jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
816 ucs.setSchemeName("Sequence Features");
819 PrintWriter out = new PrintWriter(new OutputStreamWriter(
820 new FileOutputStream(choice), "UTF-8"));
822 Set fr_colours = fr.getAllFeatureColours();
823 Iterator e = fr_colours.iterator();
824 float[] sortOrder = new float[fr_colours.size()];
825 String[] sortTypes = new String[fr_colours.size()];
829 sortTypes[i] = e.next().toString();
830 sortOrder[i] = fr.getOrder(sortTypes[i]);
833 jalview.util.QuickSort.sort(sortOrder, sortTypes);
837 for (i = 0; i < sortTypes.length; i++)
839 jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
840 col.setName(sortTypes[i]);
841 col.setRGB(jalview.util.Format.getHexString(fr.getColour(col
843 fcol = fr.getFeatureStyle(sortTypes[i]);
844 if (fcol instanceof GraduatedColor)
846 gcol = (GraduatedColor) fcol;
847 col.setMin(gcol.getMin());
848 col.setMax(gcol.getMax());
849 col.setMinRGB(jalview.util.Format.getHexString(gcol
851 col.setAutoScale(gcol.isAutoScale());
852 col.setThreshold(gcol.getThresh());
853 col.setColourByLabel(gcol.isColourByLabel());
854 switch (gcol.getThreshType())
856 case AnnotationColourGradient.NO_THRESHOLD:
857 col.setThreshType("NONE");
859 case AnnotationColourGradient.ABOVE_THRESHOLD:
860 col.setThreshType("ABOVE");
862 case AnnotationColourGradient.BELOW_THRESHOLD:
863 col.setThreshType("BELOW");
871 } catch (Exception ex)
873 ex.printStackTrace();
878 public void invertSelection()
880 for (int i = 0; i < table.getRowCount(); i++)
882 Boolean value = (Boolean) table.getValueAt(i, 2);
884 table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
888 public void orderByAvWidth()
890 if (table == null || table.getModel() == null)
894 Object[][] data = ((FeatureTableModel) table.getModel()).getData();
895 float[] width = new float[data.length];
899 for (int i = 0; i < data.length; i++)
901 awidth = (float[]) typeWidth.get(data[i][0]);
904 width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
905 // weight - but have to make per
906 // sequence, too (awidth[2])
907 // if (width[i]==1) // hack to distinguish single width sequences.
919 boolean sort = false;
920 for (int i = 0; i < width.length; i++)
922 // awidth = (float[]) typeWidth.get(data[i][0]);
925 width[i] = fr.getOrder(data[i][0].toString());
928 width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
933 width[i] /= max; // normalize
934 fr.setOrder(data[i][0].toString(), width[i]); // store for later
938 sort = sort || width[i - 1] > width[i];
943 jalview.util.QuickSort.sort(width, data);
944 // update global priority order
947 updateFeatureRenderer(data, false);
955 frame.setClosed(true);
956 } catch (Exception exe)
962 public void updateFeatureRenderer(Object[][] data)
964 updateFeatureRenderer(data, true);
967 private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
969 fr.setFeaturePriority(data, visibleNew);
970 af.alignPanel.paintAlignment(true);
973 int selectedRow = -1;
975 JTabbedPane tabbedPane = new JTabbedPane();
977 BorderLayout borderLayout1 = new BorderLayout();
979 BorderLayout borderLayout2 = new BorderLayout();
981 BorderLayout borderLayout3 = new BorderLayout();
983 JPanel bigPanel = new JPanel();
985 BorderLayout borderLayout4 = new BorderLayout();
987 JButton invert = new JButton();
989 JPanel buttonPanel = new JPanel();
991 JButton cancel = new JButton();
993 JButton ok = new JButton();
995 JButton loadColours = new JButton();
997 JButton saveColours = new JButton();
999 JPanel dasButtonPanel = new JPanel();
1001 JButton fetchDAS = new JButton();
1003 JButton saveDAS = new JButton();
1005 JButton cancelDAS = new JButton();
1007 JButton optimizeOrder = new JButton();
1009 JButton sortByScore = new JButton();
1011 JButton sortByDens = new JButton();
1013 JButton help = new JButton();
1015 JPanel transbuttons = new JPanel(new GridLayout(5, 1));
1017 private void jbInit() throws Exception
1019 this.setLayout(borderLayout1);
1020 settingsPane.setLayout(borderLayout2);
1021 dasSettingsPane.setLayout(borderLayout3);
1022 bigPanel.setLayout(borderLayout4);
1023 invert.setFont(JvSwingUtils.getLabelFont());
1024 invert.setText(MessageManager.getString("label.invert_selection"));
1025 invert.addActionListener(new ActionListener()
1027 public void actionPerformed(ActionEvent e)
1032 optimizeOrder.setFont(JvSwingUtils.getLabelFont());
1033 optimizeOrder.setText(MessageManager.getString("label.optimise_order"));
1034 optimizeOrder.addActionListener(new ActionListener()
1036 public void actionPerformed(ActionEvent e)
1041 sortByScore.setFont(JvSwingUtils.getLabelFont());
1043 .setText(MessageManager.getString("label.seq_sort_by_score"));
1044 sortByScore.addActionListener(new ActionListener()
1046 public void actionPerformed(ActionEvent e)
1048 af.avc.sortAlignmentByFeatureScore(null);
1051 sortByDens.setFont(JvSwingUtils.getLabelFont());
1052 sortByDens.setText(MessageManager
1053 .getString("label.sequence_sort_by_density"));
1054 sortByDens.addActionListener(new ActionListener()
1056 public void actionPerformed(ActionEvent e)
1058 af.avc.sortAlignmentByFeatureDensity(null);
1061 help.setFont(JvSwingUtils.getLabelFont());
1062 help.setText(MessageManager.getString("action.help"));
1063 help.addActionListener(new ActionListener()
1065 public void actionPerformed(ActionEvent e)
1069 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1070 } catch (HelpSetException e1)
1072 e1.printStackTrace();
1076 help.setFont(JvSwingUtils.getLabelFont());
1077 help.setText(MessageManager.getString("action.help"));
1078 help.addActionListener(new ActionListener()
1080 public void actionPerformed(ActionEvent e)
1084 Help.showHelpWindow(HelpId.SequenceFeatureSettings);
1085 } catch (HelpSetException e1)
1087 e1.printStackTrace();
1091 cancel.setFont(JvSwingUtils.getLabelFont());
1092 cancel.setText(MessageManager.getString("action.cancel"));
1093 cancel.addActionListener(new ActionListener()
1095 public void actionPerformed(ActionEvent e)
1097 fr.setTransparency(originalTransparency);
1098 updateFeatureRenderer(originalData);
1102 ok.setFont(JvSwingUtils.getLabelFont());
1103 ok.setText(MessageManager.getString("action.ok"));
1104 ok.addActionListener(new ActionListener()
1106 public void actionPerformed(ActionEvent e)
1111 loadColours.setFont(JvSwingUtils.getLabelFont());
1112 loadColours.setText(MessageManager.getString("label.load_colours"));
1113 loadColours.addActionListener(new ActionListener()
1115 public void actionPerformed(ActionEvent e)
1120 saveColours.setFont(JvSwingUtils.getLabelFont());
1121 saveColours.setText(MessageManager.getString("label.save_colours"));
1122 saveColours.addActionListener(new ActionListener()
1124 public void actionPerformed(ActionEvent e)
1129 transparency.addChangeListener(new ChangeListener()
1131 public void stateChanged(ChangeEvent evt)
1133 fr.setTransparency((100 - transparency.getValue()) / 100f);
1134 af.alignPanel.paintAlignment(true);
1138 transparency.setMaximum(70);
1139 transparency.setToolTipText(MessageManager
1140 .getString("label.transparency_tip"));
1141 fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
1142 fetchDAS.addActionListener(new ActionListener()
1144 public void actionPerformed(ActionEvent e)
1146 fetchDAS_actionPerformed(e);
1149 saveDAS.setText(MessageManager.getString("action.save_as_default"));
1150 saveDAS.addActionListener(new ActionListener()
1152 public void actionPerformed(ActionEvent e)
1154 saveDAS_actionPerformed(e);
1157 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
1158 dasSettingsPane.setBorder(null);
1159 cancelDAS.setEnabled(false);
1160 cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
1161 cancelDAS.addActionListener(new ActionListener()
1163 public void actionPerformed(ActionEvent e)
1165 cancelDAS_actionPerformed(e);
1168 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
1169 tabbedPane.addTab(MessageManager.getString("label.feature_settings"), settingsPane);
1170 tabbedPane.addTab(MessageManager.getString("label.das_settings"), dasSettingsPane);
1171 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
1172 transbuttons.add(optimizeOrder);
1173 transbuttons.add(invert);
1174 transbuttons.add(sortByScore);
1175 transbuttons.add(sortByDens);
1176 transbuttons.add(help);
1177 JPanel sliderPanel = new JPanel();
1178 sliderPanel.add(transparency);
1179 transPanel.add(transparency);
1180 transPanel.add(transbuttons);
1181 buttonPanel.add(ok);
1182 buttonPanel.add(cancel);
1183 buttonPanel.add(loadColours);
1184 buttonPanel.add(saveColours);
1185 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
1186 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
1187 dasButtonPanel.add(fetchDAS);
1188 dasButtonPanel.add(cancelDAS);
1189 dasButtonPanel.add(saveDAS);
1190 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
1191 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
1194 public void fetchDAS_actionPerformed(ActionEvent e)
1196 fetchDAS.setEnabled(false);
1197 cancelDAS.setEnabled(true);
1198 dassourceBrowser.setGuiEnabled(false);
1199 Vector selectedSources = dassourceBrowser.getSelectedSources();
1200 doDasFeatureFetch(selectedSources, true, true);
1204 * get the features from selectedSources for all or the current selection
1206 * @param selectedSources
1207 * @param checkDbRefs
1208 * @param promptFetchDbRefs
1210 private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
1211 boolean checkDbRefs, boolean promptFetchDbRefs)
1213 SequenceI[] dataset, seqs;
1215 AlignmentViewport vp = af.getViewport();
1216 if (vp.getSelectionGroup() != null
1217 && vp.getSelectionGroup().getSize() > 0)
1219 iSize = vp.getSelectionGroup().getSize();
1220 dataset = new SequenceI[iSize];
1221 seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
1225 iSize = vp.getAlignment().getHeight();
1226 seqs = vp.getAlignment().getSequencesArray();
1229 dataset = new SequenceI[iSize];
1230 for (int i = 0; i < iSize; i++)
1232 dataset[i] = seqs[i].getDatasetSequence();
1235 cancelDAS.setEnabled(true);
1236 dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
1237 this, selectedSources, checkDbRefs, promptFetchDbRefs);
1238 af.getViewport().setShowSequenceFeatures(true);
1239 af.showSeqFeatures.setSelected(true);
1243 * blocking call to initialise the das source browser
1245 public void initDasSources()
1247 dassourceBrowser.initDasSources();
1251 * examine the current list of das sources and return any matching the given
1252 * nicknames in sources
1255 * Vector of Strings to resolve to DAS source nicknames.
1256 * @return sources that are present in source list.
1258 public List<jalviewSourceI> resolveSourceNicknames(Vector sources)
1260 return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
1264 * get currently selected das sources. ensure you have called initDasSources
1265 * before calling this.
1267 * @return vector of selected das source nicknames
1269 public Vector getSelectedSources()
1271 return dassourceBrowser.getSelectedSources();
1275 * properly initialise DAS fetcher and then initiate a new thread to fetch
1276 * features from the named sources (rather than any turned on by default)
1280 * if true then runs in same thread, otherwise passes to the Swing
1283 public void fetchDasFeatures(Vector sources, boolean block)
1286 List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
1287 .resolveSourceNicknames(sources);
1288 if (resolved.size() == 0)
1290 resolved = dassourceBrowser.getSelectedSources();
1292 if (resolved.size() > 0)
1294 final List<jalviewSourceI> dassources = resolved;
1295 fetchDAS.setEnabled(false);
1296 // cancelDAS.setEnabled(true); doDasFetch does this.
1297 Runnable fetcher = new Runnable()
1302 doDasFeatureFetch(dassources, true, false);
1312 SwingUtilities.invokeLater(fetcher);
1317 public void saveDAS_actionPerformed(ActionEvent e)
1320 .saveProperties(jalview.bin.Cache.applicationProperties);
1323 public void complete()
1325 fetchDAS.setEnabled(true);
1326 cancelDAS.setEnabled(false);
1327 dassourceBrowser.setGuiEnabled(true);
1331 public void cancelDAS_actionPerformed(ActionEvent e)
1333 if (dasFeatureFetcher != null)
1335 dasFeatureFetcher.cancel();
1340 public void noDasSourceActive()
1344 .showInternalConfirmDialog(
1347 .getString("label.no_das_sources_selected_warn"),
1349 .getString("label.no_das_sources_selected_title"),
1350 JOptionPane.DEFAULT_OPTION,
1351 JOptionPane.INFORMATION_MESSAGE);
1354 // ///////////////////////////////////////////////////////////////////////
1355 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
1356 // ///////////////////////////////////////////////////////////////////////
1357 class FeatureTableModel extends AbstractTableModel
1359 FeatureTableModel(Object[][] data)
1364 private String[] columnNames =
1365 { MessageManager.getString("label.feature_type"), MessageManager.getString("action.colour"), MessageManager.getString("label.display") };
1367 private Object[][] data;
1369 public Object[][] getData()
1374 public void setData(Object[][] data)
1379 public int getColumnCount()
1381 return columnNames.length;
1384 public Object[] getRow(int row)
1389 public int getRowCount()
1394 public String getColumnName(int col)
1396 return columnNames[col];
1399 public Object getValueAt(int row, int col)
1401 return data[row][col];
1404 public Class getColumnClass(int c)
1406 return getValueAt(0, c).getClass();
1409 public boolean isCellEditable(int row, int col)
1411 return col == 0 ? false : true;
1414 public void setValueAt(Object value, int row, int col)
1416 data[row][col] = value;
1417 fireTableCellUpdated(row, col);
1418 updateFeatureRenderer(data);
1423 class ColorRenderer extends JLabel implements TableCellRenderer
1425 javax.swing.border.Border unselectedBorder = null;
1427 javax.swing.border.Border selectedBorder = null;
1429 final String baseTT = "Click to edit, right/apple click for menu.";
1431 public ColorRenderer()
1433 setOpaque(true); // MUST do this for background to show up.
1434 setHorizontalTextPosition(SwingConstants.CENTER);
1435 setVerticalTextPosition(SwingConstants.CENTER);
1438 public Component getTableCellRendererComponent(JTable table,
1439 Object color, boolean isSelected, boolean hasFocus, int row,
1442 // JLabel comp = new JLabel();
1446 // setBounds(getBounds());
1448 setToolTipText(baseTT);
1449 setBackground(table.getBackground());
1450 if (color instanceof GraduatedColor)
1452 Rectangle cr = table.getCellRect(row, column, false);
1453 FeatureSettings.renderGraduatedColor(this, (GraduatedColor) color,
1454 (int) cr.getWidth(), (int) cr.getHeight());
1461 newColor = (Color) color;
1463 setBackground(newColor);
1464 // comp.setToolTipText("RGB value: " + newColor.getRed() + ", "
1465 // + newColor.getGreen() + ", " + newColor.getBlue());
1469 if (selectedBorder == null)
1471 selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1472 table.getSelectionBackground());
1475 setBorder(selectedBorder);
1479 if (unselectedBorder == null)
1481 unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
1482 table.getBackground());
1485 setBorder(unselectedBorder);
1493 * update comp using rendering settings from gcol
1498 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol)
1500 int w = comp.getWidth(), h = comp.getHeight();
1503 w = (int) comp.getPreferredSize().getWidth();
1504 h = (int) comp.getPreferredSize().getHeight();
1511 renderGraduatedColor(comp, gcol, w, h);
1514 public static void renderGraduatedColor(JLabel comp, GraduatedColor gcol,
1517 boolean thr = false;
1520 if (gcol.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD)
1524 tt += "Thresholded (Above " + gcol.getThresh() + ") ";
1526 if (gcol.getThreshType() == AnnotationColourGradient.BELOW_THRESHOLD)
1530 tt += "Thresholded (Below " + gcol.getThresh() + ") ";
1532 if (gcol.isColourByLabel())
1534 tt = "Coloured by label text. " + tt;
1544 Color newColor = gcol.getMaxColor();
1545 comp.setBackground(newColor);
1546 // System.err.println("Width is " + w / 2);
1547 Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
1548 comp.setIcon(ficon);
1549 // tt+="RGB value: Max (" + newColor.getRed() + ", "
1550 // + newColor.getGreen() + ", " + newColor.getBlue()
1551 // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
1552 // + ", " + minCol.getBlue() + ")");
1554 comp.setHorizontalAlignment(SwingConstants.CENTER);
1556 if (tt.length() > 0)
1558 if (comp.getToolTipText() == null)
1560 comp.setToolTipText(tt);
1564 comp.setToolTipText(tt + " " + comp.getToolTipText());
1570 class FeatureIcon implements Icon
1572 GraduatedColor gcol;
1576 boolean midspace = false;
1578 int width = 50, height = 20;
1580 int s1, e1; // start and end of midpoint band for thresholded symbol
1582 Color mpcolour = Color.white;
1584 FeatureIcon(GraduatedColor gfc, Color bg, int w, int h, boolean mspace)
1603 public int getIconWidth()
1608 public int getIconHeight()
1613 public void paintIcon(Component c, Graphics g, int x, int y)
1616 if (gcol.isColourByLabel())
1619 g.fillRect(0, 0, width, height);
1620 // need an icon here.
1621 g.setColor(gcol.getMaxColor());
1623 g.setFont(new Font("Verdana", Font.PLAIN, 9));
1625 // g.setFont(g.getFont().deriveFont(
1626 // AffineTransform.getScaleInstance(
1627 // width/g.getFontMetrics().stringWidth("Label"),
1628 // height/g.getFontMetrics().getHeight())));
1630 g.drawString(MessageManager.getString("label.label"), 0, 0);
1635 Color minCol = gcol.getMinColor();
1637 g.fillRect(0, 0, s1, height);
1640 g.setColor(Color.white);
1641 g.fillRect(s1, 0, e1 - s1, height);
1643 g.setColor(gcol.getMaxColor());
1644 g.fillRect(0, e1, width - e1, height);
1649 class ColorEditor extends AbstractCellEditor implements TableCellEditor,
1654 GraduatedColor currentGColor;
1656 FeatureColourChooser chooser;
1664 JColorChooser colorChooser;
1668 protected static final String EDIT = "edit";
1670 int selectedRow = 0;
1672 public ColorEditor(FeatureSettings me)
1675 // Set up the editor (from the table's point of view),
1676 // which is a button.
1677 // This button brings up the color chooser dialog,
1678 // which is the editor from the user's point of view.
1679 button = new JButton();
1680 button.setActionCommand(EDIT);
1681 button.addActionListener(this);
1682 button.setBorderPainted(false);
1683 // Set up the dialog that the button brings up.
1684 colorChooser = new JColorChooser();
1685 dialog = JColorChooser.createDialog(button, "Select new Colour", true, // modal
1686 colorChooser, this, // OK button handler
1687 null); // no CANCEL button handler
1691 * Handles events from the editor button and from the dialog's OK button.
1693 public void actionPerformed(ActionEvent e)
1696 if (EDIT.equals(e.getActionCommand()))
1698 // The user has clicked the cell, so
1699 // bring up the dialog.
1700 if (currentColor != null)
1702 // bring up simple color chooser
1703 button.setBackground(currentColor);
1704 colorChooser.setColor(currentColor);
1705 dialog.setVisible(true);
1709 // bring up graduated chooser.
1710 chooser = new FeatureColourChooser(me.fr, type);
1711 chooser.setRequestFocusEnabled(true);
1712 chooser.requestFocus();
1713 chooser.addActionListener(this);
1715 // Make the renderer reappear.
1716 fireEditingStopped();
1720 { // User pressed dialog's "OK" button.
1721 if (currentColor != null)
1723 currentColor = colorChooser.getColor();
1727 // class cast exceptions may be raised if the chooser created on a
1728 // non-graduated color
1729 currentGColor = (GraduatedColor) chooser.getLastColour();
1731 me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
1732 fireEditingStopped();
1733 me.table.validate();
1737 // Implement the one CellEditor method that AbstractCellEditor doesn't.
1738 public Object getCellEditorValue()
1740 if (currentColor == null)
1742 return currentGColor;
1744 return currentColor;
1747 // Implement the one method defined by TableCellEditor.
1748 public Component getTableCellEditorComponent(JTable table, Object value,
1749 boolean isSelected, int row, int column)
1751 currentGColor = null;
1752 currentColor = null;
1753 this.selectedRow = row;
1754 type = me.table.getValueAt(row, 0).toString();
1755 button.setOpaque(true);
1756 button.setBackground(me.getBackground());
1757 if (value instanceof GraduatedColor)
1759 currentGColor = (GraduatedColor) value;
1760 JLabel btn = new JLabel();
1761 btn.setSize(button.getSize());
1762 FeatureSettings.renderGraduatedColor(btn, currentGColor);
1763 button.setBackground(btn.getBackground());
1764 button.setIcon(btn.getIcon());
1765 button.setText(btn.getText());
1770 button.setIcon(null);
1771 currentColor = (Color) value;
1772 button.setBackground(currentColor);