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 av.alignment.getSequences();
\r
52 frame = new JInternalFrame();
\r
53 frame.setContentPane(this);
\r
54 Desktop.addInternalFrame(frame, "Sequence Feature Settings", 400, 300);
\r
55 frame.setLayer(JLayeredPane.PALETTE_LAYER);
\r
59 final JSlider transparency = new JSlider(0, 70, 100 - (int)(fr.transparency*100) );
\r
60 transparency.addChangeListener(new ChangeListener()
\r
62 public void stateChanged(ChangeEvent evt)
\r
64 fr.setTransparency( (float) (100 - transparency.getValue()) / 100f);
\r
69 JPanel transPanel = new JPanel(new FlowLayout());
\r
70 transPanel.add(new JLabel("Transparency"));
\r
71 transPanel.add(transparency);
\r
72 JButton button = new JButton("Invert Selection");
\r
73 transPanel.add(button);
\r
74 button.addActionListener(new ActionListener()
\r
76 public void actionPerformed(ActionEvent evt)
\r
82 //////////////////////////////////////////////
\r
83 //We're going to need those OK cancel buttons
\r
84 JPanel buttonPanel = new JPanel(new FlowLayout());
\r
85 button = new JButton("OK");
\r
86 button.addActionListener(new ActionListener()
\r
88 public void actionPerformed(ActionEvent evt)
\r
92 frame.setClosed(true);
\r
94 catch (Exception exe)
\r
98 buttonPanel.add(button);
\r
99 button = new JButton("Cancel");
\r
100 button.addActionListener(new ActionListener()
\r
102 public void actionPerformed(ActionEvent evt)
\r
106 updateFeatureRenderer(originalData);
\r
107 frame.setClosed(true);
\r
109 catch (Exception exe)
\r
113 buttonPanel.add(button);
\r
115 button = new JButton("Load Colours");
\r
116 button.addActionListener(new ActionListener()
\r
118 public void actionPerformed(ActionEvent evt)
\r
123 buttonPanel.add(button);
\r
124 button = new JButton("Save Colours");
\r
125 button.addActionListener(new ActionListener()
\r
127 public void actionPerformed(ActionEvent evt)
\r
132 buttonPanel.add(button);
\r
134 this.setLayout(new BorderLayout());
\r
135 JPanel bigPanel = new JPanel(new BorderLayout());
\r
136 bigPanel.add(transPanel, BorderLayout.SOUTH);
\r
137 bigPanel.add(scrollPane, BorderLayout.CENTER);
\r
138 if(groupPanel!=null)
\r
140 groupPanel.setLayout(
\r
141 new GridLayout(fr.featureGroups.size() / 4 + 1, 4));
\r
143 groupPanel.validate();
\r
144 bigPanel.add(groupPanel, BorderLayout.NORTH);
\r
146 add(bigPanel, BorderLayout.CENTER);
\r
147 add(buttonPanel, BorderLayout.SOUTH);
\r
152 void setTableData()
\r
154 alignmentHasFeatures = false;
\r
156 if (fr.featureGroups == null)
\r
157 fr.featureGroups = new Hashtable();
\r
159 Vector allFeatures = new Vector();
\r
160 Vector allGroups = new Vector();
\r
161 SequenceFeature[] tmpfeatures;
\r
164 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
166 if (av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
169 alignmentHasFeatures = true;
\r
171 tmpfeatures = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
174 while (index < tmpfeatures.length)
\r
176 if(tmpfeatures[index].begin == 0 && tmpfeatures[index].end ==0)
\r
182 if(tmpfeatures[index].getFeatureGroup()!=null)
\r
184 group = tmpfeatures[index].featureGroup;
\r
185 if(!allGroups.contains(group))
\r
187 allGroups.addElement(group);
\r
189 boolean visible = true;
\r
190 if (fr.featureGroups.containsKey(group))
\r
192 visible = ( (Boolean) fr.featureGroups.get(group)).booleanValue();
\r
195 fr.featureGroups.put(group, new Boolean(visible));
\r
197 if (groupPanel == null)
\r
199 groupPanel = new JPanel();
\r
202 final JCheckBox check = new JCheckBox(group, visible);
\r
203 check.setFont(new Font("Serif", Font.BOLD, 12));
\r
204 check.addItemListener(new ItemListener()
\r
206 public void itemStateChanged(ItemEvent evt)
\r
208 fr.featureGroups.put(check.getText(),
\r
209 new Boolean(check.isSelected()));
\r
210 ap.seqPanel.seqCanvas.repaint();
\r
211 if (ap.overviewPanel != null)
\r
212 ap.overviewPanel.updateOverviewImage();
\r
217 groupPanel.add(check);
\r
223 if (!allFeatures.contains(tmpfeatures[index].getType()))
\r
225 allFeatures.addElement(tmpfeatures[index].getType());
\r
232 if(!alignmentHasFeatures)
\r
235 { frame.setClosed(true); }
\r
236 catch (Exception ex){}
\r
238 JOptionPane.showInternalMessageDialog(
\r
239 Desktop.desktop, "No features have been added to this alignment!",
\r
240 "No Sequence Features", JOptionPane.WARNING_MESSAGE);
\r
248 void resetTable(boolean groupsChanged)
\r
250 SequenceFeature [] tmpfeatures;
\r
251 String group=null, type;
\r
252 Vector visibleChecks = new Vector();
\r
254 //Find out which features should be visible depending on which groups
\r
255 //are selected / deselected
\r
256 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
258 if (av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
261 tmpfeatures = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
263 while (index < tmpfeatures.length)
\r
265 group = tmpfeatures[index].featureGroup;
\r
267 if(tmpfeatures[index].begin==0 && tmpfeatures[index].end==0)
\r
273 if (group==null || fr.featureGroups.get(group)==null ||
\r
274 ((Boolean) fr.featureGroups.get(group)).booleanValue())
\r
276 type = tmpfeatures[index].getType();
\r
277 if(!visibleChecks.contains(type) )
\r
279 visibleChecks.addElement(type);
\r
286 int fSize = visibleChecks.size();
\r
287 Object [][] data = new Object[fSize][3];
\r
290 if(fr.renderOrder!=null)
\r
292 //First add the checks in the previous render order,
\r
293 //in case the window has been closed and reopened
\r
294 for(int ro=fr.renderOrder.length-1; ro>-1; ro--)
\r
296 type = fr.renderOrder[ro];
\r
298 if(!visibleChecks.contains(type))
\r
301 data[dataIndex][0] = type;
\r
302 data[dataIndex][1] = fr.getColour(type);
\r
303 data[dataIndex][2] = new Boolean(av.featuresDisplayed.containsKey(type));
\r
305 visibleChecks.removeElement(type);
\r
309 fSize = visibleChecks.size();
\r
310 for(int i=0; i<fSize; i++)
\r
312 //These must be extra features belonging to the group
\r
313 //which was just selected
\r
314 type = visibleChecks.elementAt(i).toString();
\r
315 data[dataIndex][0] = type;
\r
317 data[dataIndex][1] = fr.getColour(type);
\r
318 data[dataIndex][2] = new Boolean(true);
\r
322 if(originalData==null)
\r
324 originalData = new Object[data.length][3];
\r
325 System.arraycopy(data,0,originalData,0,data.length);
\r
328 table = new JTable(new FeatureTableModel(data));
\r
329 scrollPane.setViewportView(table);
\r
330 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
\r
331 table.setFont(new Font("Verdana", Font.PLAIN, 12));
\r
332 table.setDefaultRenderer(Color.class,
\r
333 new ColorRenderer());
\r
335 table.setDefaultEditor(Color.class,
\r
336 new ColorEditor());
\r
338 table.getColumnModel().getColumn(0).setPreferredWidth(200);
\r
340 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
\r
342 table.addMouseListener(new MouseAdapter()
\r
344 public void mousePressed(MouseEvent evt)
\r
346 selectedRow = table.rowAtPoint(evt.getPoint());
\r
350 table.addMouseMotionListener(new MouseMotionAdapter()
\r
352 public void mouseDragged(MouseEvent evt)
\r
354 int newRow = table.rowAtPoint(evt.getPoint());
\r
355 if(newRow!=selectedRow
\r
359 Object[] temp = new Object[3];
\r
360 temp[0] = table.getValueAt(selectedRow, 0);
\r
361 temp[1] = table.getValueAt(selectedRow, 1);
\r
362 temp[2] = table.getValueAt(selectedRow, 2);
\r
364 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
\r
365 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
\r
366 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
\r
368 table.setValueAt(temp[0], newRow, 0);
\r
369 table.setValueAt(temp[1], newRow, 1);
\r
370 table.setValueAt(temp[2], newRow, 2);
\r
372 selectedRow = newRow;
\r
377 updateFeatureRenderer(data);
\r
383 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
384 "LAST_DIRECTORY"), new String[] { "fc" },
\r
385 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
386 chooser.setFileView(new jalview.io.JalviewFileView());
\r
387 chooser.setDialogTitle("Load Feature Colours");
\r
388 chooser.setToolTipText("Load");
\r
390 int value = chooser.showOpenDialog(this);
\r
392 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
394 File file = chooser.getSelectedFile();
\r
398 InputStreamReader in = new InputStreamReader(new FileInputStream(
\r
401 jalview.binding.JalviewUserColours jucs = new jalview.binding.
\r
402 JalviewUserColours();
\r
403 jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);
\r
406 for (int i = 0; i < jucs.getColourCount(); i++)
\r
408 fr.setColour( jucs.getColour(i).getName(),
\r
409 new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));
\r
415 catch (Exception ex)
\r
417 System.out.println("Error loading User ColourFile\n" + ex);
\r
424 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
425 "LAST_DIRECTORY"), new String[] { "fc" },
\r
426 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
427 chooser.setFileView(new jalview.io.JalviewFileView());
\r
428 chooser.setDialogTitle("Save Feature Colour Scheme");
\r
429 chooser.setToolTipText("Save");
\r
431 int value = chooser.showSaveDialog(this);
\r
433 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
435 String choice = chooser.getSelectedFile().getPath();
\r
436 jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();
\r
437 ucs.setSchemeName("Sequence Features");
\r
440 PrintWriter out = new PrintWriter(new OutputStreamWriter(
\r
441 new FileOutputStream(choice), "UTF-8"));
\r
443 Enumeration e = fr.featureColours.keys();
\r
444 while(e.hasMoreElements())
\r
446 jalview.binding.Colour col = new jalview.binding.Colour();
\r
447 col.setName(e.nextElement().toString());
\r
448 col.setRGB(jalview.util.Format.getHexString(
\r
449 fr.getColour(col.getName())));
\r
450 ucs.addColour(col);
\r
456 catch (Exception ex)
\r
458 ex.printStackTrace();
\r
463 public void invertSelection()
\r
465 for(int i=0; i<table.getRowCount(); i++)
\r
467 Boolean value = (Boolean)table.getValueAt(i,2);
\r
470 new Boolean(!value.booleanValue()),
\r
476 public void updateFeatureRenderer(Object [][] data)
\r
478 fr.setFeaturePriority( data );
\r
481 if(ap.overviewPanel!=null)
\r
482 ap.overviewPanel.updateOverviewImage();
\r
485 int selectedRow =-1;
\r
488 /////////////////////////////////////////////////////////////////////////
\r
489 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
\r
490 /////////////////////////////////////////////////////////////////////////
\r
491 class FeatureTableModel
\r
492 extends AbstractTableModel
\r
494 FeatureTableModel(Object[][] data)
\r
499 private String[] columnNames = {"Feature Type", "Colour","Display"};
\r
500 private Object[][] data;
\r
502 public Object[][] getData()
\r
507 public void setData(Object[][] data)
\r
512 public int getColumnCount() {
\r
513 return columnNames.length;
\r
516 public Object[] getRow(int row)
\r
521 public int getRowCount() {
\r
522 return data.length;
\r
525 public String getColumnName(int col) {
\r
526 return columnNames[col];
\r
529 public Object getValueAt(int row, int col) {
\r
530 return data[row][col];
\r
533 public Class getColumnClass(int c) {
\r
534 return getValueAt(0, c).getClass();
\r
537 public boolean isCellEditable(int row, int col) {
\r
538 return col==0 ? false:true;
\r
541 public void setValueAt(Object value, int row, int col) {
\r
542 data[row][col] = value;
\r
543 fireTableCellUpdated(row, col);
\r
544 updateFeatureRenderer(data);
\r
548 class ColorRenderer extends JLabel
\r
549 implements TableCellRenderer {
\r
550 javax.swing.border.Border unselectedBorder = null;
\r
551 javax.swing.border.Border selectedBorder = null;
\r
553 public ColorRenderer() {
\r
554 setOpaque(true); //MUST do this for background to show up.
\r
557 public Component getTableCellRendererComponent(
\r
558 JTable table, Object color,
\r
559 boolean isSelected, boolean hasFocus,
\r
560 int row, int column) {
\r
561 Color newColor = (Color)color;
\r
562 setBackground(newColor);
\r
564 if (selectedBorder == null) {
\r
565 selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
566 table.getSelectionBackground());
\r
568 setBorder(selectedBorder);
\r
570 if (unselectedBorder == null) {
\r
571 unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
572 table.getBackground());
\r
574 setBorder(unselectedBorder);
\r
577 setToolTipText("RGB value: " + newColor.getRed() + ", "
\r
578 + newColor.getGreen() + ", "
\r
579 + newColor.getBlue());
\r
585 class ColorEditor extends AbstractCellEditor
\r
586 implements TableCellEditor,
\r
588 Color currentColor;
\r
590 JColorChooser colorChooser;
\r
592 protected static final String EDIT = "edit";
\r
594 public ColorEditor() {
\r
595 //Set up the editor (from the table's point of view),
\r
596 //which is a button.
\r
597 //This button brings up the color chooser dialog,
\r
598 //which is the editor from the user's point of view.
\r
599 button = new JButton();
\r
600 button.setActionCommand(EDIT);
\r
601 button.addActionListener(this);
\r
602 button.setBorderPainted(false);
\r
603 //Set up the dialog that the button brings up.
\r
604 colorChooser = new JColorChooser();
\r
605 dialog = JColorChooser.createDialog(button,
\r
606 "Select new Colour",
\r
609 this, //OK button handler
\r
610 null); //no CANCEL button handler
\r
614 * Handles events from the editor button and from
\r
615 * the dialog's OK button.
\r
617 public void actionPerformed(ActionEvent e) {
\r
619 if (EDIT.equals(e.getActionCommand())) {
\r
620 //The user has clicked the cell, so
\r
621 //bring up the dialog.
\r
622 button.setBackground(currentColor);
\r
623 colorChooser.setColor(currentColor);
\r
624 dialog.setVisible(true);
\r
626 //Make the renderer reappear.
\r
627 fireEditingStopped();
\r
629 } else { //User pressed dialog's "OK" button.
\r
630 currentColor = colorChooser.getColor();
\r
634 //Implement the one CellEditor method that AbstractCellEditor doesn't.
\r
635 public Object getCellEditorValue() {
\r
636 return currentColor;
\r
639 //Implement the one method defined by TableCellEditor.
\r
640 public Component getTableCellEditorComponent(JTable table,
\r
642 boolean isSelected,
\r
645 currentColor = (Color)value;
\r