/* * Jalview - A Sequence Alignment Editor and Viewer * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ package jalview.gui; import jalview.datamodel.*; import javax.swing.*; import javax.swing.event.*; import java.awt.*; import java.util.*; import javax.swing.BorderFactory; import java.awt.event.*; import javax.swing.table.*; import java.io.*; import jalview.io.JalviewFileChooser; public class FeatureSettings extends JPanel { final FeatureRenderer fr; final AlignmentPanel ap; final AlignViewport av; Hashtable allFeatures; Object [][] originalData; final JInternalFrame frame; JScrollPane scrollPane = new JScrollPane(); JTable table; JPanel groupPanel; public FeatureSettings(AlignViewport av, final AlignmentPanel ap) { this.ap = ap; this.av = av; fr = ap.seqPanel.seqCanvas.getFeatureRenderer(); av.alignment.getSequences(); frame = new JInternalFrame(); frame.setContentPane(this); Desktop.addInternalFrame(frame, "Sequence Feature Settings", 400, 300); setTableData(); final JSlider transparency = new JSlider(0, 70, 0); transparency.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent evt) { fr.setTransparency( (float) (100 - transparency.getValue()) / 100f); ap.repaint(); } }); JPanel transPanel = new JPanel(new FlowLayout()); transPanel.add(new JLabel("Transparency")); transPanel.add(transparency); ////////////////////////////////////////////// //We're going to need those OK cancel buttons JPanel buttonPanel = new JPanel(new FlowLayout()); JButton button = new JButton("OK"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { try { frame.setClosed(true); } catch (Exception exe) {} } }); buttonPanel.add(button); button = new JButton("Cancel"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { try { updateFeatureRenderer(originalData); frame.setClosed(true); } catch (Exception exe) {} } }); buttonPanel.add(button); button = new JButton("Load Colours"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { load(); } }); buttonPanel.add(button); button = new JButton("Save Colours"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { save(); } }); buttonPanel.add(button); this.setLayout(new BorderLayout()); JPanel bigPanel = new JPanel(new BorderLayout()); bigPanel.add(transPanel, BorderLayout.SOUTH); bigPanel.add(scrollPane, BorderLayout.CENTER); if(groupPanel!=null) { groupPanel.setLayout( new GridLayout(groupPanel.getComponentCount()/3, 4)); groupPanel.validate(); bigPanel.add(groupPanel, BorderLayout.NORTH); } add(bigPanel, BorderLayout.CENTER); add(buttonPanel, BorderLayout.SOUTH); } void setTableData() { if (fr.featureGroups == null) fr.featureGroups = new Hashtable(); else fr.featureGroups.clear(); allFeatures = new Hashtable(); SequenceFeature[] features; for (int i = 0; i < av.alignment.getHeight(); i++) { features = av.alignment.getSequenceAt(i).getDatasetSequence(). getSequenceFeatures(); if (features == null) continue; int index = 0; while (index < features.length) { if(features[index].getFeatureGroup()!=null && !fr.featureGroups.containsKey(features[index].getFeatureGroup())) { fr.featureGroups.put(features[index].getFeatureGroup(), new Boolean(true)); if(groupPanel==null) groupPanel = new JPanel(); final JCheckBox check = new JCheckBox(features[index].getFeatureGroup(), true); check.setFont(new Font("Serif", Font.BOLD, 12)); check.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent evt) { if (fr.featureGroups.containsKey(check.getText())) { fr.featureGroups.put(check.getText(), new Boolean(check.isSelected())); ap.seqPanel.seqCanvas.repaint(); if (ap.overviewPanel != null) ap.overviewPanel.updateOverviewImage(); } resetTable(); } }); groupPanel.add(check); } if (!allFeatures.contains(features[index].getType())) { if(features[index].featureGroup!=null) allFeatures.put(features[index].getType(), features[index].featureGroup); else allFeatures.put(features[index].getType(), "NOGROUP"); } index++; } } if(allFeatures.size()<1) { try { frame.setClosed(true); } catch (Exception ex){} JOptionPane.showInternalMessageDialog( Desktop.desktop, "No features have been added to this alignment!", "No Sequence Features", JOptionPane.WARNING_MESSAGE); return; } resetTable(); } void resetTable() { int fSize = allFeatures.size(); String type; boolean originalExists = false; if (originalData != null) originalExists = true; else originalData = new Object[fSize][3]; Object[][] tmp = new Object[fSize][3]; int tmpIndex = 0; Enumeration en = allFeatures.keys(); int i=0; while(en.hasMoreElements()) { type = en.nextElement().toString(); Color col = fr.getColour(type); //This will ignore any features which are in groups not shown if(fr.featureGroups==null || ((Boolean)fr.featureGroups.get(allFeatures.get(type))).booleanValue()) { tmp[tmpIndex][0] = type; tmp[tmpIndex][1] = col; if (av.featuresDisplayed != null) tmp[tmpIndex][2] = new Boolean(av.featuresDisplayed.containsKey(type)); else tmp[tmpIndex][2] = new Boolean(true); tmpIndex++; } if (!originalExists) { originalData[i][0] = type; originalData[i][1] = col; if (av.featuresDisplayed != null) originalData[i][2] = new Boolean(av.featuresDisplayed.contains(type)); else originalData[i][2] = new Boolean(true); } i++; } Object [][]data = new Object[tmpIndex][3]; System.arraycopy(tmp, 0, data,0, tmpIndex); table = new JTable(new FeatureTableModel(data)); scrollPane.setViewportView(table); table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12)); table.setFont(new Font("Verdana", Font.PLAIN, 12)); table.setDefaultRenderer(Color.class, new ColorRenderer()); table.setDefaultEditor(Color.class, new ColorEditor()); table.getColumnModel().getColumn(0).setPreferredWidth(200); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); table.addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent evt) { selectedRow = table.rowAtPoint(evt.getPoint()); } }); table.addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent evt) { int newRow = table.rowAtPoint(evt.getPoint()); if(newRow!=selectedRow && selectedRow!=-1 && newRow!=-1) { Object[] temp = new Object[3]; temp[0] = table.getValueAt(selectedRow, 0); temp[1] = table.getValueAt(selectedRow, 1); temp[2] = table.getValueAt(selectedRow, 2); table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0); table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1); table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2); table.setValueAt(temp[0], newRow, 0); table.setValueAt(temp[1], newRow, 1); table.setValueAt(temp[2], newRow, 2); selectedRow = newRow; } } }); updateFeatureRenderer(data); } void load() { JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty( "LAST_DIRECTORY"), new String[] { "fc" }, new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours"); chooser.setFileView(new jalview.io.JalviewFileView()); chooser.setDialogTitle("Load Feature Colours"); chooser.setToolTipText("Load"); int value = chooser.showOpenDialog(this); if (value == JalviewFileChooser.APPROVE_OPTION) { File file = chooser.getSelectedFile(); try { InputStreamReader in = new InputStreamReader(new FileInputStream( file), "UTF-8"); jalview.binding.JalviewUserColours jucs = new jalview.binding. JalviewUserColours(); jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in); for (int i = 0; i < jucs.getColourCount(); i++) { fr.setColour( jucs.getColour(i).getName(), new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16))); } setTableData(); ap.repaint(); } catch (Exception ex) { System.out.println("Error loading User ColourFile\n" + ex); } } } void save() { JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty( "LAST_DIRECTORY"), new String[] { "fc" }, new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours"); chooser.setFileView(new jalview.io.JalviewFileView()); chooser.setDialogTitle("Save Feature Colour Scheme"); chooser.setToolTipText("Save"); int value = chooser.showSaveDialog(this); if (value == JalviewFileChooser.APPROVE_OPTION) { String choice = chooser.getSelectedFile().getPath(); jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours(); ucs.setSchemeName("Sequence Features"); try { PrintWriter out = new PrintWriter(new OutputStreamWriter( new FileOutputStream(choice), "UTF-8")); Enumeration e = fr.featureColours.keys(); while(e.hasMoreElements()) { jalview.binding.Colour col = new jalview.binding.Colour(); col.setName(e.nextElement().toString()); col.setRGB(jalview.util.Format.getHexString( fr.getColour(col.getName()))); ucs.addColour(col); } ucs.marshal(out); out.close(); } catch (Exception ex) { ex.printStackTrace(); } } } public void updateFeatureRenderer(Object [][] data) { fr.setFeaturePriority( data ); ap.repaint(); if(ap.overviewPanel!=null) ap.overviewPanel.updateOverviewImage(); } int selectedRow =-1; ///////////////////////////////////////////////////////////////////////// // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html ///////////////////////////////////////////////////////////////////////// class FeatureTableModel extends AbstractTableModel { FeatureTableModel(Object[][] data) { this.data = data; } private String[] columnNames = {"Feature Type", "Colour","Display"}; private Object[][] data; public Object[][] getData() { return data; } public int getColumnCount() { return columnNames.length; } public Object[] getRow(int row) { return data[row]; } public int getRowCount() { return data.length; } public String getColumnName(int col) { return columnNames[col]; } public Object getValueAt(int row, int col) { return data[row][col]; } public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } public boolean isCellEditable(int row, int col) { return col==0 ? false:true; } public void setValueAt(Object value, int row, int col) { data[row][col] = value; fireTableCellUpdated(row, col); updateFeatureRenderer(data); } } class ColorRenderer extends JLabel implements TableCellRenderer { javax.swing.border.Border unselectedBorder = null; javax.swing.border.Border selectedBorder = null; public ColorRenderer() { setOpaque(true); //MUST do this for background to show up. } public Component getTableCellRendererComponent( JTable table, Object color, boolean isSelected, boolean hasFocus, int row, int column) { Color newColor = (Color)color; setBackground(newColor); if (isSelected) { if (selectedBorder == null) { selectedBorder = BorderFactory.createMatteBorder(2,5,2,5, table.getSelectionBackground()); } setBorder(selectedBorder); } else { if (unselectedBorder == null) { unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5, table.getBackground()); } setBorder(unselectedBorder); } setToolTipText("RGB value: " + newColor.getRed() + ", " + newColor.getGreen() + ", " + newColor.getBlue()); return this; } } } class ColorEditor extends AbstractCellEditor implements TableCellEditor, ActionListener { Color currentColor; JButton button; JColorChooser colorChooser; JDialog dialog; protected static final String EDIT = "edit"; public ColorEditor() { //Set up the editor (from the table's point of view), //which is a button. //This button brings up the color chooser dialog, //which is the editor from the user's point of view. button = new JButton(); button.setActionCommand(EDIT); button.addActionListener(this); button.setBorderPainted(false); //Set up the dialog that the button brings up. colorChooser = new JColorChooser(); dialog = JColorChooser.createDialog(button, "Select new Colour", true, //modal colorChooser, this, //OK button handler null); //no CANCEL button handler } /** * Handles events from the editor button and from * the dialog's OK button. */ public void actionPerformed(ActionEvent e) { if (EDIT.equals(e.getActionCommand())) { //The user has clicked the cell, so //bring up the dialog. button.setBackground(currentColor); colorChooser.setColor(currentColor); dialog.setVisible(true); //Make the renderer reappear. fireEditingStopped(); } else { //User pressed dialog's "OK" button. currentColor = colorChooser.getColor(); } } //Implement the one CellEditor method that AbstractCellEditor doesn't. public Object getCellEditorValue() { return currentColor; } //Implement the one method defined by TableCellEditor. public Component getTableCellEditorComponent(JTable table, Object value, boolean isSelected, int row, int column) { currentColor = (Color)value; return button; } }