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 if (data[dataIndex][1] == null)
\r
299 //"Colour has been updated in another view!!"
\r
300 fr.renderOrder = null;
\r
304 data[dataIndex][2] = new Boolean(true);
\r
308 if(originalData==null)
\r
310 originalData = new Object[data.length][3];
\r
311 System.arraycopy(data,0,originalData,0,data.length);
\r
314 table.setModel(new FeatureTableModel(data));
\r
315 table.getColumnModel().getColumn(0).setPreferredWidth(200);
\r
318 if (groupPanel != null)
\r
320 groupPanel.setLayout(
\r
321 new GridLayout(fr.featureGroups.size() / 4 + 1, 4));
\r
323 groupPanel.validate();
\r
324 bigPanel.add(groupPanel, BorderLayout.NORTH);
\r
327 updateFeatureRenderer(data);
\r
333 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
334 "LAST_DIRECTORY"), new String[] { "fc" },
\r
335 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
336 chooser.setFileView(new jalview.io.JalviewFileView());
\r
337 chooser.setDialogTitle("Load Feature Colours");
\r
338 chooser.setToolTipText("Load");
\r
340 int value = chooser.showOpenDialog(this);
\r
342 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
344 File file = chooser.getSelectedFile();
\r
348 InputStreamReader in = new InputStreamReader(new FileInputStream(
\r
351 jalview.binding.JalviewUserColours jucs = new jalview.binding.
\r
352 JalviewUserColours();
\r
353 jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);
\r
356 for (int i = 0; i < jucs.getColourCount(); i++)
\r
358 fr.setColour( jucs.getColour(i).getName(),
\r
359 new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));
\r
363 af.alignPanel.repaint();
\r
365 catch (Exception ex)
\r
367 System.out.println("Error loading User Colour File\n" + ex);
\r
374 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
375 "LAST_DIRECTORY"), new String[] { "fc" },
\r
376 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
377 chooser.setFileView(new jalview.io.JalviewFileView());
\r
378 chooser.setDialogTitle("Save Feature Colour Scheme");
\r
379 chooser.setToolTipText("Save");
\r
381 int value = chooser.showSaveDialog(this);
\r
383 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
385 String choice = chooser.getSelectedFile().getPath();
\r
386 jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();
\r
387 ucs.setSchemeName("Sequence Features");
\r
390 PrintWriter out = new PrintWriter(new OutputStreamWriter(
\r
391 new FileOutputStream(choice), "UTF-8"));
\r
393 Enumeration e = fr.featureColours.keys();
\r
394 while(e.hasMoreElements())
\r
396 jalview.binding.Colour col = new jalview.binding.Colour();
\r
397 col.setName(e.nextElement().toString());
\r
398 col.setRGB(jalview.util.Format.getHexString(
\r
399 fr.getColour(col.getName())));
\r
400 ucs.addColour(col);
\r
406 catch (Exception ex)
\r
408 ex.printStackTrace();
\r
413 public void invertSelection()
\r
415 for(int i=0; i<table.getRowCount(); i++)
\r
417 Boolean value = (Boolean)table.getValueAt(i,2);
\r
420 new Boolean(!value.booleanValue()),
\r
425 public void close()
\r
429 frame.setClosed(true);
\r
431 catch (Exception exe)
\r
436 public void updateFeatureRenderer(Object [][] data)
\r
438 fr.setFeaturePriority( data );
\r
439 af.alignPanel.repaint();
\r
441 if(af.alignPanel.overviewPanel!=null)
\r
442 af.alignPanel.overviewPanel.updateOverviewImage();
\r
445 int selectedRow =-1;
\r
446 JTabbedPane tabbedPane = new JTabbedPane();
\r
447 BorderLayout borderLayout1 = new BorderLayout();
\r
448 BorderLayout borderLayout2 = new BorderLayout();
\r
449 BorderLayout borderLayout3 = new BorderLayout();
\r
450 JPanel bigPanel = new JPanel();
\r
451 BorderLayout borderLayout4 = new BorderLayout();
\r
452 JButton invert = new JButton();
\r
453 JPanel buttonPanel = new JPanel();
\r
454 JButton cancel = new JButton();
\r
455 JButton ok = new JButton();
\r
456 JButton loadColours = new JButton();
\r
457 JButton saveColours = new JButton();
\r
458 JPanel dasButtonPanel = new JPanel();
\r
459 JButton fetchDAS = new JButton();
\r
460 JButton saveDAS = new JButton();
\r
461 JButton cancelDAS = new JButton();
\r
462 private void jbInit()
\r
465 this.setLayout(borderLayout1);
\r
466 settingsPane.setLayout(borderLayout2);
\r
467 dasSettingsPane.setLayout(borderLayout3);
\r
468 bigPanel.setLayout(borderLayout4);
\r
469 invert.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
470 invert.setText("Invert Selection");
\r
471 invert.addActionListener(new ActionListener()
\r
473 public void actionPerformed(ActionEvent e)
\r
478 cancel.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
479 cancel.setText("Cancel");
\r
480 cancel.addActionListener(new ActionListener()
\r
482 public void actionPerformed(ActionEvent e)
\r
484 updateFeatureRenderer(originalData);
\r
488 ok.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
490 ok.addActionListener(new ActionListener()
\r
492 public void actionPerformed(ActionEvent e)
\r
497 loadColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
498 loadColours.setText("Load Colours");
\r
499 loadColours.addActionListener(new ActionListener()
\r
501 public void actionPerformed(ActionEvent e)
\r
506 saveColours.setFont(new java.awt.Font("Verdana", Font.PLAIN, 11));
\r
507 saveColours.setText("Save Colours");
\r
508 saveColours.addActionListener(new ActionListener()
\r
510 public void actionPerformed(ActionEvent e)
\r
515 transparency.addChangeListener(new ChangeListener()
\r
517 public void stateChanged(ChangeEvent evt)
\r
519 fr.setTransparency( (float) (100 - transparency.getValue()) / 100f);
\r
520 af.alignPanel.repaint();
\r
525 transparency.setMaximum(70);
\r
526 fetchDAS.setText("Fetch DAS Features");
\r
527 fetchDAS.addActionListener(new ActionListener()
\r
529 public void actionPerformed(ActionEvent e)
\r
531 fetchDAS_actionPerformed(e);
\r
534 saveDAS.setText("Save as default");
\r
535 saveDAS.addActionListener(new ActionListener()
\r
537 public void actionPerformed(ActionEvent e)
\r
539 saveDAS_actionPerformed(e);
\r
542 dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
\r
543 dasSettingsPane.setBorder(null);
\r
544 cancelDAS.setEnabled(false);
\r
545 cancelDAS.setText("Cancel Fetch");
\r
546 cancelDAS.addActionListener(new ActionListener()
\r
548 public void actionPerformed(ActionEvent e)
\r
550 cancelDAS_actionPerformed(e);
\r
553 this.add(tabbedPane, java.awt.BorderLayout.CENTER);
\r
554 tabbedPane.addTab("Feature Settings", settingsPane );
\r
555 tabbedPane.addTab("DAS Settings", dasSettingsPane);
\r
556 bigPanel.add(transPanel, java.awt.BorderLayout.SOUTH);
\r
557 transPanel.add(transparency);
\r
558 transPanel.add(invert);
\r
559 buttonPanel.add(ok);
\r
560 buttonPanel.add(cancel);
\r
561 buttonPanel.add(loadColours);
\r
562 buttonPanel.add(saveColours);
\r
563 bigPanel.add(scrollPane, java.awt.BorderLayout.CENTER);
\r
564 dasSettingsPane.add(dasButtonPanel, java.awt.BorderLayout.SOUTH);
\r
565 dasButtonPanel.add(fetchDAS);
\r
566 dasButtonPanel.add(cancelDAS);
\r
567 dasButtonPanel.add(saveDAS);
\r
568 settingsPane.add(bigPanel, java.awt.BorderLayout.CENTER);
\r
569 settingsPane.add(buttonPanel, java.awt.BorderLayout.SOUTH);
\r
572 public void fetchDAS_actionPerformed(ActionEvent e)
\r
574 fetchDAS.setEnabled(false);
\r
575 cancelDAS.setEnabled(true);
\r
576 Vector selectedSources = dassourceBrowser.getSelectedSources();
\r
578 SequenceI [] dataset, seqs ;
\r
581 if(af.getViewport().getSelectionGroup()!=null
\r
582 && af.getViewport().getSelectionGroup().getSize()>0)
\r
584 iSize = af.getViewport().getSelectionGroup().getSize();
\r
585 dataset = new SequenceI[iSize];
\r
586 seqs = af.getViewport().getSelectionGroup().
\r
587 getSequencesInOrder(
\r
588 af.getViewport().getAlignment());
\r
592 iSize = af.getViewport().getAlignment().getHeight();
\r
593 seqs = af.getViewport().getAlignment().getSequencesArray();
\r
596 dataset = new SequenceI[iSize];
\r
597 for (int i = 0; i < iSize; i++)
\r
599 dataset[i] = seqs[i].getDatasetSequence();
\r
602 dasFeatureFetcher =
\r
603 new jalview.io.DasSequenceFeatureFetcher(
\r
608 af.getViewport().setShowSequenceFeatures(true);
\r
609 af.showSeqFeatures.setSelected(true);
\r
612 public void saveDAS_actionPerformed(ActionEvent e)
\r
614 dassourceBrowser.saveProperties(jalview.bin.Cache.applicationProperties);
\r
617 public void complete()
\r
619 fetchDAS.setEnabled(true);
\r
620 cancelDAS.setEnabled(false);
\r
623 public void cancelDAS_actionPerformed(ActionEvent e)
\r
625 dasFeatureFetcher.cancel();
\r
626 fetchDAS.setEnabled(true);
\r
627 cancelDAS.setEnabled(false);
\r
630 /////////////////////////////////////////////////////////////////////////
\r
631 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
\r
632 /////////////////////////////////////////////////////////////////////////
\r
633 class FeatureTableModel
\r
634 extends AbstractTableModel
\r
636 FeatureTableModel(Object[][] data)
\r
641 private String[] columnNames = {"Feature Type", "Colour","Display"};
\r
642 private Object[][] data;
\r
644 public Object[][] getData()
\r
649 public void setData(Object[][] data)
\r
654 public int getColumnCount() {
\r
655 return columnNames.length;
\r
658 public Object[] getRow(int row)
\r
663 public int getRowCount() {
\r
664 return data.length;
\r
667 public String getColumnName(int col) {
\r
668 return columnNames[col];
\r
671 public Object getValueAt(int row, int col) {
\r
672 return data[row][col];
\r
675 public Class getColumnClass(int c) {
\r
676 return getValueAt(0, c).getClass();
\r
679 public boolean isCellEditable(int row, int col) {
\r
680 return col==0 ? false:true;
\r
683 public void setValueAt(Object value, int row, int col) {
\r
684 data[row][col] = value;
\r
685 fireTableCellUpdated(row, col);
\r
686 updateFeatureRenderer(data);
\r
690 class ColorRenderer extends JLabel
\r
691 implements TableCellRenderer {
\r
692 javax.swing.border.Border unselectedBorder = null;
\r
693 javax.swing.border.Border selectedBorder = null;
\r
695 public ColorRenderer() {
\r
696 setOpaque(true); //MUST do this for background to show up.
\r
699 public Component getTableCellRendererComponent(
\r
700 JTable table, Object color,
\r
701 boolean isSelected, boolean hasFocus,
\r
702 int row, int column) {
\r
703 Color newColor = (Color)color;
\r
704 setBackground(newColor);
\r
706 if (selectedBorder == null) {
\r
707 selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
708 table.getSelectionBackground());
\r
710 setBorder(selectedBorder);
\r
712 if (unselectedBorder == null) {
\r
713 unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
714 table.getBackground());
\r
716 setBorder(unselectedBorder);
\r
719 setToolTipText("RGB value: " + newColor.getRed() + ", "
\r
720 + newColor.getGreen() + ", "
\r
721 + newColor.getBlue());
\r
727 class ColorEditor extends AbstractCellEditor
\r
728 implements TableCellEditor,
\r
730 Color currentColor;
\r
732 JColorChooser colorChooser;
\r
734 protected static final String EDIT = "edit";
\r
736 public ColorEditor() {
\r
737 //Set up the editor (from the table's point of view),
\r
738 //which is a button.
\r
739 //This button brings up the color chooser dialog,
\r
740 //which is the editor from the user's point of view.
\r
741 button = new JButton();
\r
742 button.setActionCommand(EDIT);
\r
743 button.addActionListener(this);
\r
744 button.setBorderPainted(false);
\r
745 //Set up the dialog that the button brings up.
\r
746 colorChooser = new JColorChooser();
\r
747 dialog = JColorChooser.createDialog(button,
\r
748 "Select new Colour",
\r
751 this, //OK button handler
\r
752 null); //no CANCEL button handler
\r
756 * Handles events from the editor button and from
\r
757 * the dialog's OK button.
\r
759 public void actionPerformed(ActionEvent e) {
\r
761 if (EDIT.equals(e.getActionCommand())) {
\r
762 //The user has clicked the cell, so
\r
763 //bring up the dialog.
\r
764 button.setBackground(currentColor);
\r
765 colorChooser.setColor(currentColor);
\r
766 dialog.setVisible(true);
\r
768 //Make the renderer reappear.
\r
769 fireEditingStopped();
\r
771 } else { //User pressed dialog's "OK" button.
\r
772 currentColor = colorChooser.getColor();
\r
776 //Implement the one CellEditor method that AbstractCellEditor doesn't.
\r
777 public Object getCellEditorValue() {
\r
778 return currentColor;
\r
781 //Implement the one method defined by TableCellEditor.
\r
782 public Component getTableCellEditorComponent(JTable table,
\r
784 boolean isSelected,
\r
787 currentColor = (Color)value;
\r