2 * Jalview - A Sequence Alignment Editor and Viewer
\r
3 * Copyright (C) 2006 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle
\r
5 * This program is free software; you can redistribute it and/or
\r
6 * modify it under the terms of the GNU General Public License
\r
7 * as published by the Free Software Foundation; either version 2
\r
8 * of the License, or (at your option) any later version.
\r
10 * This program is distributed in the hope that it will be useful,
\r
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 * GNU General Public License for more details.
\r
15 * You should have received a copy of the GNU General Public License
\r
16 * along with this program; if not, write to the Free Software
\r
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
\r
19 package jalview.gui;
\r
21 import jalview.datamodel.*;
\r
22 import javax.swing.*;
\r
23 import javax.swing.event.*;
\r
26 import javax.swing.BorderFactory;
\r
27 import java.awt.event.*;
\r
28 import javax.swing.table.*;
\r
30 import jalview.io.JalviewFileChooser;
\r
31 import java.awt.BorderLayout;
\r
32 import java.awt.Font;
\r
33 import java.awt.Color;
\r
35 public class FeatureSettings extends JPanel
\r
37 DasSourceBrowser dassourceBrowser;
\r
38 jalview.io.DasSequenceFeatureFetcher dasFeatureFetcher;
\r
39 JPanel settingsPane = new JPanel();
\r
40 JPanel dasSettingsPane = new JPanel();
\r
42 final FeatureRenderer fr;
\r
43 public final AlignFrame af;
\r
44 Object [][] originalData;
\r
45 final JInternalFrame frame;
\r
46 JScrollPane scrollPane = new JScrollPane();
\r
49 JSlider transparency = new JSlider();
\r
51 JPanel transPanel = new JPanel(new FlowLayout());
\r
53 public FeatureSettings(AlignFrame af)
\r
56 fr = af.getFeatureRenderer();
\r
58 transparency.setMaximum( 100 - (int)(fr.transparency*100) ) ;
\r
64 catch (Exception ex)
\r
66 ex.printStackTrace();
\r
69 table = new JTable();
\r
70 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
\r
71 table.setFont(new Font("Verdana", Font.PLAIN, 12));
\r
72 table.setDefaultRenderer(Color.class,
\r
73 new ColorRenderer());
\r
75 table.setDefaultEditor(Color.class,
\r
78 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
\r
80 table.addMouseListener(new MouseAdapter()
\r
82 public void mousePressed(MouseEvent evt)
\r
84 selectedRow = table.rowAtPoint(evt.getPoint());
\r
88 table.addMouseMotionListener(new MouseMotionAdapter()
\r
90 public void mouseDragged(MouseEvent evt)
\r
92 int newRow = table.rowAtPoint(evt.getPoint());
\r
93 if (newRow != selectedRow
\r
94 && selectedRow != -1
\r
97 Object[] temp = new Object[3];
\r
98 temp[0] = table.getValueAt(selectedRow, 0);
\r
99 temp[1] = table.getValueAt(selectedRow, 1);
\r
100 temp[2] = table.getValueAt(selectedRow, 2);
\r
102 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
\r
103 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
\r
104 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
\r
106 table.setValueAt(temp[0], newRow, 0);
\r
107 table.setValueAt(temp[1], newRow, 1);
\r
108 table.setValueAt(temp[2], newRow, 2);
\r
110 selectedRow = newRow;
\r
115 scrollPane.setViewportView(table);
\r
117 dassourceBrowser = new DasSourceBrowser();
\r
118 dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
\r
122 if (af.getViewport().featuresDisplayed == null || fr.renderOrder==null)
\r
123 fr.findAllFeatures();
\r
127 frame = new JInternalFrame();
\r
128 frame.setContentPane(this);
\r
129 Desktop.addInternalFrame(frame, "Sequence Feature Settings", 400, 450);
\r
130 frame.setLayer(JLayeredPane.PALETTE_LAYER);
\r
133 synchronized public void setTableData()
\r
135 if (fr.featureGroups == null)
\r
136 fr.featureGroups = new Hashtable();
\r
138 Vector allFeatures = new Vector();
\r
139 Vector allGroups = new Vector();
\r
140 SequenceFeature[] tmpfeatures;
\r
143 for (int i = 0; i < af.getViewport().alignment.getHeight(); i++)
\r
145 if (af.getViewport().alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
148 tmpfeatures = af.getViewport().alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
151 while (index < tmpfeatures.length)
\r
153 if(tmpfeatures[index].begin == 0 && tmpfeatures[index].end ==0)
\r
159 if(tmpfeatures[index].getFeatureGroup()!=null)
\r
161 group = tmpfeatures[index].featureGroup;
\r
162 if(!allGroups.contains(group))
\r
164 allGroups.addElement(group);
\r
166 boolean visible = true;
\r
167 if (fr.featureGroups.containsKey(group))
\r
169 visible = ( (Boolean) fr.featureGroups.get(group)).booleanValue();
\r
172 if (groupPanel == null)
\r
174 groupPanel = new JPanel();
\r
177 boolean alreadyAdded = false;
\r
178 for(int g=0; g<groupPanel.getComponentCount(); g++)
\r
180 if(((JCheckBox)groupPanel.getComponent(g))
\r
181 .getText().equals(group))
\r
183 alreadyAdded = true;
\r
191 fr.featureGroups.put(group, new Boolean(visible));
\r
193 final JCheckBox check = new JCheckBox(group, visible);
\r
194 check.setFont(new Font("Serif", Font.BOLD, 12));
\r
195 check.addItemListener(new ItemListener()
\r
197 public void itemStateChanged(ItemEvent evt)
\r
199 fr.featureGroups.put(check.getText(),
\r
200 new Boolean(check.isSelected()));
\r
201 af.alignPanel.seqPanel.seqCanvas.repaint();
\r
202 if (af.alignPanel.overviewPanel != null)
\r
203 af.alignPanel.overviewPanel.updateOverviewImage();
\r
208 groupPanel.add(check);
\r
212 if (!allFeatures.contains(tmpfeatures[index].getType()))
\r
214 allFeatures.addElement(tmpfeatures[index].getType());
\r
226 void resetTable(boolean groupsChanged)
\r
228 SequenceFeature [] tmpfeatures;
\r
229 String group=null, type;
\r
230 Vector visibleChecks = new Vector();
\r
232 //Find out which features should be visible depending on which groups
\r
233 //are selected / deselected
\r
234 for (int i = 0; i < af.getViewport().alignment.getHeight(); i++)
\r
237 tmpfeatures = af.getViewport().alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
238 if (tmpfeatures == null)
\r
242 while (index < tmpfeatures.length)
\r
244 group = tmpfeatures[index].featureGroup;
\r
246 if(tmpfeatures[index].begin==0 && tmpfeatures[index].end==0)
\r
252 if (group==null || fr.featureGroups.get(group)==null ||
\r
253 ((Boolean) fr.featureGroups.get(group)).booleanValue())
\r
255 type = tmpfeatures[index].getType();
\r
256 if(!visibleChecks.contains(type) )
\r
258 visibleChecks.addElement(type);
\r
265 int fSize = visibleChecks.size();
\r
266 Object [][] data = new Object[fSize][3];
\r
269 if(fr.renderOrder!=null)
\r
271 //First add the checks in the previous render order,
\r
272 //in case the window has been closed and reopened
\r
273 for(int ro=fr.renderOrder.length-1; ro>-1; ro--)
\r
275 type = fr.renderOrder[ro];
\r
277 if(!visibleChecks.contains(type))
\r
280 data[dataIndex][0] = type;
\r
281 data[dataIndex][1] = fr.getColour(type);
\r
282 data[dataIndex][2] = new Boolean(af.getViewport().featuresDisplayed.containsKey(type));
\r
284 visibleChecks.removeElement(type);
\r
288 fSize = visibleChecks.size();
\r
289 for(int i=0; i<fSize; i++)
\r
291 //These must be extra features belonging to the group
\r
292 //which was just selected
\r
293 type = visibleChecks.elementAt(i).toString();
\r
294 data[dataIndex][0] = type;
\r
296 data[dataIndex][1] = fr.getColour(type);
\r
297 data[dataIndex][2] = new Boolean(true);
\r
301 if(originalData==null)
\r
303 originalData = new Object[data.length][3];
\r
304 System.arraycopy(data,0,originalData,0,data.length);
\r
307 table.setModel(new FeatureTableModel(data));
\r
308 table.getColumnModel().getColumn(0).setPreferredWidth(200);
\r
311 if (groupPanel != null)
\r
313 groupPanel.setLayout(
\r
314 new GridLayout(fr.featureGroups.size() / 4 + 1, 4));
\r
316 groupPanel.validate();
\r
317 bigPanel.add(groupPanel, BorderLayout.NORTH);
\r
320 updateFeatureRenderer(data);
\r
326 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
327 "LAST_DIRECTORY"), new String[] { "fc" },
\r
328 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
329 chooser.setFileView(new jalview.io.JalviewFileView());
\r
330 chooser.setDialogTitle("Load Feature Colours");
\r
331 chooser.setToolTipText("Load");
\r
333 int value = chooser.showOpenDialog(this);
\r
335 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
337 File file = chooser.getSelectedFile();
\r
341 InputStreamReader in = new InputStreamReader(new FileInputStream(
\r
344 jalview.binding.JalviewUserColours jucs = new jalview.binding.
\r
345 JalviewUserColours();
\r
346 jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);
\r
349 for (int i = 0; i < jucs.getColourCount(); i++)
\r
351 fr.setColour( jucs.getColour(i).getName(),
\r
352 new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));
\r
356 af.alignPanel.repaint();
\r
358 catch (Exception ex)
\r
360 System.out.println("Error loading User Colour File\n" + ex);
\r
367 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
368 "LAST_DIRECTORY"), new String[] { "fc" },
\r
369 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
370 chooser.setFileView(new jalview.io.JalviewFileView());
\r
371 chooser.setDialogTitle("Save Feature Colour Scheme");
\r
372 chooser.setToolTipText("Save");
\r
374 int value = chooser.showSaveDialog(this);
\r
376 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
378 String choice = chooser.getSelectedFile().getPath();
\r
379 jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();
\r
380 ucs.setSchemeName("Sequence Features");
\r
383 PrintWriter out = new PrintWriter(new OutputStreamWriter(
\r
384 new FileOutputStream(choice), "UTF-8"));
\r
386 Enumeration e = fr.featureColours.keys();
\r
387 while(e.hasMoreElements())
\r
389 jalview.binding.Colour col = new jalview.binding.Colour();
\r
390 col.setName(e.nextElement().toString());
\r
391 col.setRGB(jalview.util.Format.getHexString(
\r
392 fr.getColour(col.getName())));
\r
393 ucs.addColour(col);
\r
399 catch (Exception ex)
\r
401 ex.printStackTrace();
\r
406 public void invertSelection()
\r
408 for(int i=0; i<table.getRowCount(); i++)
\r
410 Boolean value = (Boolean)table.getValueAt(i,2);
\r
413 new Boolean(!value.booleanValue()),
\r
418 public void close()
\r
422 frame.setClosed(true);
\r
424 catch (Exception exe)
\r
429 public void updateFeatureRenderer(Object [][] data)
\r
431 fr.setFeaturePriority( data );
\r
432 af.alignPanel.repaint();
\r
434 if(af.alignPanel.overviewPanel!=null)
\r
435 af.alignPanel.overviewPanel.updateOverviewImage();
\r
438 int selectedRow =-1;
\r
439 JTabbedPane tabbedPane = new JTabbedPane();
\r
440 BorderLayout borderLayout1 = new BorderLayout();
\r
441 BorderLayout borderLayout2 = new BorderLayout();
\r
442 BorderLayout borderLayout3 = new BorderLayout();
\r
443 JPanel bigPanel = new JPanel();
\r
444 BorderLayout borderLayout4 = new BorderLayout();
\r
445 JButton invert = new JButton();
\r
446 JPanel buttonPanel = new JPanel();
\r
447 JButton cancel = new JButton();
\r
448 JButton ok = new JButton();
\r
449 JButton loadColours = new JButton();
\r
450 JButton saveColours = new JButton();
\r
451 JPanel dasButtonPanel = new JPanel();
\r
452 JButton fetchDAS = new JButton();
\r
453 JButton saveDAS = new JButton();
\r
454 JButton cancelDAS = new JButton();
\r
455 private void jbInit()
\r
458 this.setLayout(borderLayout1);
\r
459 settingsPane.setLayout(borderLayout2);
\r
460 dasSettingsPane.setLayout(borderLayout3);
\r
461 bigPanel.setLayout(borderLayout4);
\r
462 invert.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
463 invert.setText("Invert Selection");
\r
464 invert.addActionListener(new ActionListener()
\r
466 public void actionPerformed(ActionEvent e)
\r
471 cancel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
472 cancel.setText("Cancel");
\r
473 cancel.addActionListener(new ActionListener()
\r
475 public void actionPerformed(ActionEvent e)
\r
477 updateFeatureRenderer(originalData);
\r
481 ok.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
483 ok.addActionListener(new ActionListener()
\r
485 public void actionPerformed(ActionEvent e)
\r
490 loadColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
491 loadColours.setText("Load Colours");
\r
492 loadColours.addActionListener(new ActionListener()
\r
494 public void actionPerformed(ActionEvent e)
\r
499 saveColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
500 saveColours.setText("Save Colours");
\r
501 saveColours.addActionListener(new ActionListener()
\r
503 public void actionPerformed(ActionEvent e)
\r
508 transparency.addChangeListener(new ChangeListener()
\r
510 public void stateChanged(ChangeEvent evt)
\r
512 fr.setTransparency( (float) (100 - transparency.getValue()) / 100f);
\r
513 af.alignPanel.repaint();
\r
518 transparency.setMaximum(70);
\r
519 fetchDAS.setText("Fetch DAS Features");
\r
520 fetchDAS.addActionListener(new ActionListener()
\r
522 public void actionPerformed(ActionEvent e)
\r
524 fetchDAS_actionPerformed(e);
\r
527 saveDAS.setText("Save as default");
\r
528 saveDAS.addActionListener(new ActionListener()
\r
530 public void actionPerformed(ActionEvent e)
\r
532 saveDAS_actionPerformed(e);
\r
535 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
\r
536 dasSettingsPane.setBorder(null);
\r
537 cancelDAS.setEnabled(false);
\r
538 cancelDAS.setText("Cancel Fetch");
\r
539 cancelDAS.addActionListener(new ActionListener()
\r
541 public void actionPerformed(ActionEvent e)
\r
543 cancelDAS_actionPerformed(e);
\r
546 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
\r
547 tabbedPane.addTab("Feature Settings", settingsPane );
\r
548 tabbedPane.addTab("DAS Settings", dasSettingsPane);
\r
549 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
\r
550 transPanel.add(transparency);
\r
551 transPanel.add(invert);
\r
552 buttonPanel.add(ok);
\r
553 buttonPanel.add(cancel);
\r
554 buttonPanel.add(loadColours);
\r
555 buttonPanel.add(saveColours);
\r
556 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
\r
557 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
\r
558 dasButtonPanel.add(fetchDAS);
\r
559 dasButtonPanel.add(cancelDAS);
\r
560 dasButtonPanel.add(saveDAS);
\r
561 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
\r
562 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
\r
565 public void fetchDAS_actionPerformed(ActionEvent e)
\r
567 fetchDAS.setEnabled(false);
\r
568 cancelDAS.setEnabled(true);
\r
569 Vector selectedSources = dassourceBrowser.getSelectedSources();
\r
571 SequenceI [] dataset, seqs ;
\r
574 if(af.getViewport().getSelectionGroup()!=null
\r
575 && af.getViewport().getSelectionGroup().getSize(false)>0)
\r
577 iSize = af.getViewport().getSelectionGroup().getSize(false);
\r
578 dataset = new SequenceI[iSize];
\r
579 seqs = af.getViewport().getSelectionGroup().
\r
580 getSequencesInOrder(
\r
581 af.getViewport().getAlignment());
\r
585 iSize = af.getViewport().getAlignment().getHeight();
\r
586 seqs = af.getViewport().getAlignment().getSequencesArray();
\r
589 dataset = new SequenceI[iSize];
\r
590 for (int i = 0; i < iSize; i++)
\r
592 dataset[i] = seqs[i].getDatasetSequence();
\r
595 dasFeatureFetcher =
\r
596 new jalview.io.DasSequenceFeatureFetcher(
\r
601 af.getViewport().setShowSequenceFeatures(true);
\r
602 af.showSeqFeatures.setSelected(true);
\r
605 public void saveDAS_actionPerformed(ActionEvent e)
\r
607 dassourceBrowser.saveProperties(jalview.bin.Cache.applicationProperties);
\r
610 public void complete()
\r
612 fetchDAS.setEnabled(true);
\r
613 cancelDAS.setEnabled(false);
\r
616 public void cancelDAS_actionPerformed(ActionEvent e)
\r
618 dasFeatureFetcher.cancel();
\r
619 fetchDAS.setEnabled(true);
\r
620 cancelDAS.setEnabled(false);
\r
623 /////////////////////////////////////////////////////////////////////////
\r
624 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
\r
625 /////////////////////////////////////////////////////////////////////////
\r
626 class FeatureTableModel
\r
627 extends AbstractTableModel
\r
629 FeatureTableModel(Object[][] data)
\r
634 private String[] columnNames = {"Feature Type", "Colour","Display"};
\r
635 private Object[][] data;
\r
637 public Object[][] getData()
\r
642 public void setData(Object[][] data)
\r
647 public int getColumnCount() {
\r
648 return columnNames.length;
\r
651 public Object[] getRow(int row)
\r
656 public int getRowCount() {
\r
657 return data.length;
\r
660 public String getColumnName(int col) {
\r
661 return columnNames[col];
\r
664 public Object getValueAt(int row, int col) {
\r
665 return data[row][col];
\r
668 public Class getColumnClass(int c) {
\r
669 return getValueAt(0, c).getClass();
\r
672 public boolean isCellEditable(int row, int col) {
\r
673 return col==0 ? false:true;
\r
676 public void setValueAt(Object value, int row, int col) {
\r
677 data[row][col] = value;
\r
678 fireTableCellUpdated(row, col);
\r
679 updateFeatureRenderer(data);
\r
683 class ColorRenderer extends JLabel
\r
684 implements TableCellRenderer {
\r
685 javax.swing.border.Border unselectedBorder = null;
\r
686 javax.swing.border.Border selectedBorder = null;
\r
688 public ColorRenderer() {
\r
689 setOpaque(true); //MUST do this for background to show up.
\r
692 public Component getTableCellRendererComponent(
\r
693 JTable table, Object color,
\r
694 boolean isSelected, boolean hasFocus,
\r
695 int row, int column) {
\r
696 Color newColor = (Color)color;
\r
697 setBackground(newColor);
\r
699 if (selectedBorder == null) {
\r
700 selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
701 table.getSelectionBackground());
\r
703 setBorder(selectedBorder);
\r
705 if (unselectedBorder == null) {
\r
706 unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
707 table.getBackground());
\r
709 setBorder(unselectedBorder);
\r
712 setToolTipText("RGB value: " + newColor.getRed() + ", "
\r
713 + newColor.getGreen() + ", "
\r
714 + newColor.getBlue());
\r
720 class ColorEditor extends AbstractCellEditor
\r
721 implements TableCellEditor,
\r
723 Color currentColor;
\r
725 JColorChooser colorChooser;
\r
727 protected static final String EDIT = "edit";
\r
729 public ColorEditor() {
\r
730 //Set up the editor (from the table's point of view),
\r
731 //which is a button.
\r
732 //This button brings up the color chooser dialog,
\r
733 //which is the editor from the user's point of view.
\r
734 button = new JButton();
\r
735 button.setActionCommand(EDIT);
\r
736 button.addActionListener(this);
\r
737 button.setBorderPainted(false);
\r
738 //Set up the dialog that the button brings up.
\r
739 colorChooser = new JColorChooser();
\r
740 dialog = JColorChooser.createDialog(button,
\r
741 "Select new Colour",
\r
744 this, //OK button handler
\r
745 null); //no CANCEL button handler
\r
749 * Handles events from the editor button and from
\r
750 * the dialog's OK button.
\r
752 public void actionPerformed(ActionEvent e) {
\r
754 if (EDIT.equals(e.getActionCommand())) {
\r
755 //The user has clicked the cell, so
\r
756 //bring up the dialog.
\r
757 button.setBackground(currentColor);
\r
758 colorChooser.setColor(currentColor);
\r
759 dialog.setVisible(true);
\r
761 //Make the renderer reappear.
\r
762 fireEditingStopped();
\r
764 } else { //User pressed dialog's "OK" button.
\r
765 currentColor = colorChooser.getColor();
\r
769 //Implement the one CellEditor method that AbstractCellEditor doesn't.
\r
770 public Object getCellEditorValue() {
\r
771 return currentColor;
\r
774 //Implement the one method defined by TableCellEditor.
\r
775 public Component getTableCellEditorComponent(JTable table,
\r
777 boolean isSelected,
\r
780 currentColor = (Color)value;
\r