2 * Jalview - A Sequence Alignment Editor and Viewer
\r
3 * Copyright (C) 2005 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
32 public class FeatureSettings extends JPanel
\r
35 final FeatureRenderer fr;
\r
36 final AlignmentPanel ap;
\r
37 final AlignViewport av;
\r
38 Object [][] originalData;
\r
39 final JInternalFrame frame;
\r
40 JScrollPane scrollPane = new JScrollPane();
\r
44 boolean alignmentHasFeatures = false;
\r
46 public FeatureSettings(AlignViewport av, final AlignmentPanel ap)
\r
50 fr = ap.seqPanel.seqCanvas.getFeatureRenderer();
\r
51 if (av.featuresDisplayed == null || fr.renderOrder==null)
\r
52 fr.findAllFeatures();
\r
54 frame = new JInternalFrame();
\r
55 frame.setContentPane(this);
\r
56 Desktop.addInternalFrame(frame, "Sequence Feature Settings", 400, 300);
\r
57 frame.setLayer(JLayeredPane.PALETTE_LAYER);
\r
61 final JSlider transparency = new JSlider(0, 70, 100 - (int)(fr.transparency*100) );
\r
62 transparency.addChangeListener(new ChangeListener()
\r
64 public void stateChanged(ChangeEvent evt)
\r
66 fr.setTransparency( (float) (100 - transparency.getValue()) / 100f);
\r
71 JPanel transPanel = new JPanel(new FlowLayout());
\r
72 transPanel.add(new JLabel("Transparency"));
\r
73 transPanel.add(transparency);
\r
74 JButton button = new JButton("Invert Selection");
\r
75 transPanel.add(button);
\r
76 button.addActionListener(new ActionListener()
\r
78 public void actionPerformed(ActionEvent evt)
\r
84 //////////////////////////////////////////////
\r
85 //We're going to need those OK cancel buttons
\r
86 JPanel buttonPanel = new JPanel(new FlowLayout());
\r
87 button = new JButton("OK");
\r
88 button.addActionListener(new ActionListener()
\r
90 public void actionPerformed(ActionEvent evt)
\r
94 frame.setClosed(true);
\r
96 catch (Exception exe)
\r
100 buttonPanel.add(button);
\r
101 button = new JButton("Cancel");
\r
102 button.addActionListener(new ActionListener()
\r
104 public void actionPerformed(ActionEvent evt)
\r
108 updateFeatureRenderer(originalData);
\r
109 frame.setClosed(true);
\r
111 catch (Exception exe)
\r
115 buttonPanel.add(button);
\r
117 button = new JButton("Load Colours");
\r
118 button.addActionListener(new ActionListener()
\r
120 public void actionPerformed(ActionEvent evt)
\r
125 buttonPanel.add(button);
\r
126 button = new JButton("Save Colours");
\r
127 button.addActionListener(new ActionListener()
\r
129 public void actionPerformed(ActionEvent evt)
\r
134 buttonPanel.add(button);
\r
136 this.setLayout(new BorderLayout());
\r
137 JPanel bigPanel = new JPanel(new BorderLayout());
\r
138 bigPanel.add(transPanel, BorderLayout.SOUTH);
\r
139 bigPanel.add(scrollPane, BorderLayout.CENTER);
\r
140 if(groupPanel!=null)
\r
142 groupPanel.setLayout(
\r
143 new GridLayout(fr.featureGroups.size() / 4 + 1, 4));
\r
145 groupPanel.validate();
\r
146 bigPanel.add(groupPanel, BorderLayout.NORTH);
\r
148 add(bigPanel, BorderLayout.CENTER);
\r
149 add(buttonPanel, BorderLayout.SOUTH);
\r
154 void setTableData()
\r
156 alignmentHasFeatures = false;
\r
158 if (fr.featureGroups == null)
\r
159 fr.featureGroups = new Hashtable();
\r
161 Vector allFeatures = new Vector();
\r
162 Vector allGroups = new Vector();
\r
163 SequenceFeature[] tmpfeatures;
\r
166 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
168 if (av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
171 alignmentHasFeatures = true;
\r
173 tmpfeatures = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
176 while (index < tmpfeatures.length)
\r
178 if(tmpfeatures[index].begin == 0 && tmpfeatures[index].end ==0)
\r
184 if(tmpfeatures[index].getFeatureGroup()!=null)
\r
186 group = tmpfeatures[index].featureGroup;
\r
187 if(!allGroups.contains(group))
\r
189 allGroups.addElement(group);
\r
191 boolean visible = true;
\r
192 if (fr.featureGroups.containsKey(group))
\r
194 visible = ( (Boolean) fr.featureGroups.get(group)).booleanValue();
\r
197 fr.featureGroups.put(group, new Boolean(visible));
\r
199 if (groupPanel == null)
\r
201 groupPanel = new JPanel();
\r
204 final JCheckBox check = new JCheckBox(group, visible);
\r
205 check.setFont(new Font("Serif", Font.BOLD, 12));
\r
206 check.addItemListener(new ItemListener()
\r
208 public void itemStateChanged(ItemEvent evt)
\r
210 fr.featureGroups.put(check.getText(),
\r
211 new Boolean(check.isSelected()));
\r
212 ap.seqPanel.seqCanvas.repaint();
\r
213 if (ap.overviewPanel != null)
\r
214 ap.overviewPanel.updateOverviewImage();
\r
219 groupPanel.add(check);
\r
225 if (!allFeatures.contains(tmpfeatures[index].getType()))
\r
227 allFeatures.addElement(tmpfeatures[index].getType());
\r
234 if(!alignmentHasFeatures)
\r
237 { frame.setClosed(true); }
\r
238 catch (Exception ex){}
\r
240 JOptionPane.showInternalMessageDialog(
\r
241 Desktop.desktop, "No features have been added to this alignment!",
\r
242 "No Sequence Features", JOptionPane.WARNING_MESSAGE);
\r
250 void resetTable(boolean groupsChanged)
\r
252 SequenceFeature [] tmpfeatures;
\r
253 String group=null, type;
\r
254 Vector visibleChecks = new Vector();
\r
256 //Find out which features should be visible depending on which groups
\r
257 //are selected / deselected
\r
258 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
260 if (av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
263 tmpfeatures = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
265 while (index < tmpfeatures.length)
\r
267 group = tmpfeatures[index].featureGroup;
\r
269 if(tmpfeatures[index].begin==0 && tmpfeatures[index].end==0)
\r
275 if (group==null || fr.featureGroups.get(group)==null ||
\r
276 ((Boolean) fr.featureGroups.get(group)).booleanValue())
\r
278 type = tmpfeatures[index].getType();
\r
279 if(!visibleChecks.contains(type) )
\r
281 visibleChecks.addElement(type);
\r
288 int fSize = visibleChecks.size();
\r
289 Object [][] data = new Object[fSize][3];
\r
292 if(fr.renderOrder!=null)
\r
294 //First add the checks in the previous render order,
\r
295 //in case the window has been closed and reopened
\r
296 for(int ro=fr.renderOrder.length-1; ro>-1; ro--)
\r
298 type = fr.renderOrder[ro];
\r
300 if(!visibleChecks.contains(type))
\r
303 data[dataIndex][0] = type;
\r
304 data[dataIndex][1] = fr.getColour(type);
\r
305 data[dataIndex][2] = new Boolean(av.featuresDisplayed.containsKey(type));
\r
307 visibleChecks.removeElement(type);
\r
311 fSize = visibleChecks.size();
\r
312 for(int i=0; i<fSize; i++)
\r
314 //These must be extra features belonging to the group
\r
315 //which was just selected
\r
316 type = visibleChecks.elementAt(i).toString();
\r
317 data[dataIndex][0] = type;
\r
319 data[dataIndex][1] = fr.getColour(type);
\r
320 data[dataIndex][2] = new Boolean(true);
\r
324 if(originalData==null)
\r
326 originalData = new Object[data.length][3];
\r
327 System.arraycopy(data,0,originalData,0,data.length);
\r
330 table = new JTable(new FeatureTableModel(data));
\r
331 scrollPane.setViewportView(table);
\r
332 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
\r
333 table.setFont(new Font("Verdana", Font.PLAIN, 12));
\r
334 table.setDefaultRenderer(Color.class,
\r
335 new ColorRenderer());
\r
337 table.setDefaultEditor(Color.class,
\r
338 new ColorEditor());
\r
340 table.getColumnModel().getColumn(0).setPreferredWidth(200);
\r
342 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
\r
344 table.addMouseListener(new MouseAdapter()
\r
346 public void mousePressed(MouseEvent evt)
\r
348 selectedRow = table.rowAtPoint(evt.getPoint());
\r
352 table.addMouseMotionListener(new MouseMotionAdapter()
\r
354 public void mouseDragged(MouseEvent evt)
\r
356 int newRow = table.rowAtPoint(evt.getPoint());
\r
357 if(newRow!=selectedRow
\r
361 Object[] temp = new Object[3];
\r
362 temp[0] = table.getValueAt(selectedRow, 0);
\r
363 temp[1] = table.getValueAt(selectedRow, 1);
\r
364 temp[2] = table.getValueAt(selectedRow, 2);
\r
366 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
\r
367 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
\r
368 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
\r
370 table.setValueAt(temp[0], newRow, 0);
\r
371 table.setValueAt(temp[1], newRow, 1);
\r
372 table.setValueAt(temp[2], newRow, 2);
\r
374 selectedRow = newRow;
\r
379 updateFeatureRenderer(data);
\r
385 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
386 "LAST_DIRECTORY"), new String[] { "fc" },
\r
387 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
388 chooser.setFileView(new jalview.io.JalviewFileView());
\r
389 chooser.setDialogTitle("Load Feature Colours");
\r
390 chooser.setToolTipText("Load");
\r
392 int value = chooser.showOpenDialog(this);
\r
394 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
396 File file = chooser.getSelectedFile();
\r
400 InputStreamReader in = new InputStreamReader(new FileInputStream(
\r
403 jalview.binding.JalviewUserColours jucs = new jalview.binding.
\r
404 JalviewUserColours();
\r
405 jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);
\r
408 for (int i = 0; i < jucs.getColourCount(); i++)
\r
410 fr.setColour( jucs.getColour(i).getName(),
\r
411 new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));
\r
417 catch (Exception ex)
\r
419 System.out.println("Error loading User ColourFile\n" + ex);
\r
426 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
427 "LAST_DIRECTORY"), new String[] { "fc" },
\r
428 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
429 chooser.setFileView(new jalview.io.JalviewFileView());
\r
430 chooser.setDialogTitle("Save Feature Colour Scheme");
\r
431 chooser.setToolTipText("Save");
\r
433 int value = chooser.showSaveDialog(this);
\r
435 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
437 String choice = chooser.getSelectedFile().getPath();
\r
438 jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();
\r
439 ucs.setSchemeName("Sequence Features");
\r
442 PrintWriter out = new PrintWriter(new OutputStreamWriter(
\r
443 new FileOutputStream(choice), "UTF-8"));
\r
445 Enumeration e = fr.featureColours.keys();
\r
446 while(e.hasMoreElements())
\r
448 jalview.binding.Colour col = new jalview.binding.Colour();
\r
449 col.setName(e.nextElement().toString());
\r
450 col.setRGB(jalview.util.Format.getHexString(
\r
451 fr.getColour(col.getName())));
\r
452 ucs.addColour(col);
\r
458 catch (Exception ex)
\r
460 ex.printStackTrace();
\r
465 public void invertSelection()
\r
467 for(int i=0; i<table.getRowCount(); i++)
\r
469 Boolean value = (Boolean)table.getValueAt(i,2);
\r
472 new Boolean(!value.booleanValue()),
\r
478 public void updateFeatureRenderer(Object [][] data)
\r
480 fr.setFeaturePriority( data );
\r
483 if(ap.overviewPanel!=null)
\r
484 ap.overviewPanel.updateOverviewImage();
\r
487 int selectedRow =-1;
\r
490 /////////////////////////////////////////////////////////////////////////
\r
491 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
\r
492 /////////////////////////////////////////////////////////////////////////
\r
493 class FeatureTableModel
\r
494 extends AbstractTableModel
\r
496 FeatureTableModel(Object[][] data)
\r
501 private String[] columnNames = {"Feature Type", "Colour","Display"};
\r
502 private Object[][] data;
\r
504 public Object[][] getData()
\r
509 public void setData(Object[][] data)
\r
514 public int getColumnCount() {
\r
515 return columnNames.length;
\r
518 public Object[] getRow(int row)
\r
523 public int getRowCount() {
\r
524 return data.length;
\r
527 public String getColumnName(int col) {
\r
528 return columnNames[col];
\r
531 public Object getValueAt(int row, int col) {
\r
532 return data[row][col];
\r
535 public Class getColumnClass(int c) {
\r
536 return getValueAt(0, c).getClass();
\r
539 public boolean isCellEditable(int row, int col) {
\r
540 return col==0 ? false:true;
\r
543 public void setValueAt(Object value, int row, int col) {
\r
544 data[row][col] = value;
\r
545 fireTableCellUpdated(row, col);
\r
546 updateFeatureRenderer(data);
\r
550 class ColorRenderer extends JLabel
\r
551 implements TableCellRenderer {
\r
552 javax.swing.border.Border unselectedBorder = null;
\r
553 javax.swing.border.Border selectedBorder = null;
\r
555 public ColorRenderer() {
\r
556 setOpaque(true); //MUST do this for background to show up.
\r
559 public Component getTableCellRendererComponent(
\r
560 JTable table, Object color,
\r
561 boolean isSelected, boolean hasFocus,
\r
562 int row, int column) {
\r
563 Color newColor = (Color)color;
\r
564 setBackground(newColor);
\r
566 if (selectedBorder == null) {
\r
567 selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
568 table.getSelectionBackground());
\r
570 setBorder(selectedBorder);
\r
572 if (unselectedBorder == null) {
\r
573 unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
574 table.getBackground());
\r
576 setBorder(unselectedBorder);
\r
579 setToolTipText("RGB value: " + newColor.getRed() + ", "
\r
580 + newColor.getGreen() + ", "
\r
581 + newColor.getBlue());
\r
587 class ColorEditor extends AbstractCellEditor
\r
588 implements TableCellEditor,
\r
590 Color currentColor;
\r
592 JColorChooser colorChooser;
\r
594 protected static final String EDIT = "edit";
\r
596 public ColorEditor() {
\r
597 //Set up the editor (from the table's point of view),
\r
598 //which is a button.
\r
599 //This button brings up the color chooser dialog,
\r
600 //which is the editor from the user's point of view.
\r
601 button = new JButton();
\r
602 button.setActionCommand(EDIT);
\r
603 button.addActionListener(this);
\r
604 button.setBorderPainted(false);
\r
605 //Set up the dialog that the button brings up.
\r
606 colorChooser = new JColorChooser();
\r
607 dialog = JColorChooser.createDialog(button,
\r
608 "Select new Colour",
\r
611 this, //OK button handler
\r
612 null); //no CANCEL button handler
\r
616 * Handles events from the editor button and from
\r
617 * the dialog's OK button.
\r
619 public void actionPerformed(ActionEvent e) {
\r
621 if (EDIT.equals(e.getActionCommand())) {
\r
622 //The user has clicked the cell, so
\r
623 //bring up the dialog.
\r
624 button.setBackground(currentColor);
\r
625 colorChooser.setColor(currentColor);
\r
626 dialog.setVisible(true);
\r
628 //Make the renderer reappear.
\r
629 fireEditingStopped();
\r
631 } else { //User pressed dialog's "OK" button.
\r
632 currentColor = colorChooser.getColor();
\r
636 //Implement the one CellEditor method that AbstractCellEditor doesn't.
\r
637 public Object getCellEditorValue() {
\r
638 return currentColor;
\r
641 //Implement the one method defined by TableCellEditor.
\r
642 public Component getTableCellEditorComponent(JTable table,
\r
644 boolean isSelected,
\r
647 currentColor = (Color)value;
\r