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 if(fr.getColour(type)==null)
\r
318 fr.createRandomColour(type);
\r
320 data[dataIndex][1] = fr.getColour(type);
\r
321 data[dataIndex][2] = new Boolean(true);
\r
325 if(originalData==null)
\r
327 originalData = new Object[data.length][3];
\r
328 System.arraycopy(data,0,originalData,0,data.length);
\r
331 table = new JTable(new FeatureTableModel(data));
\r
332 scrollPane.setViewportView(table);
\r
333 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
\r
334 table.setFont(new Font("Verdana", Font.PLAIN, 12));
\r
335 table.setDefaultRenderer(Color.class,
\r
336 new ColorRenderer());
\r
338 table.setDefaultEditor(Color.class,
\r
339 new ColorEditor());
\r
341 table.getColumnModel().getColumn(0).setPreferredWidth(200);
\r
343 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
\r
345 table.addMouseListener(new MouseAdapter()
\r
347 public void mousePressed(MouseEvent evt)
\r
349 selectedRow = table.rowAtPoint(evt.getPoint());
\r
353 table.addMouseMotionListener(new MouseMotionAdapter()
\r
355 public void mouseDragged(MouseEvent evt)
\r
357 int newRow = table.rowAtPoint(evt.getPoint());
\r
358 if(newRow!=selectedRow
\r
362 Object[] temp = new Object[3];
\r
363 temp[0] = table.getValueAt(selectedRow, 0);
\r
364 temp[1] = table.getValueAt(selectedRow, 1);
\r
365 temp[2] = table.getValueAt(selectedRow, 2);
\r
367 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
\r
368 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
\r
369 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
\r
371 table.setValueAt(temp[0], newRow, 0);
\r
372 table.setValueAt(temp[1], newRow, 1);
\r
373 table.setValueAt(temp[2], newRow, 2);
\r
375 selectedRow = newRow;
\r
380 updateFeatureRenderer(data);
\r
386 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
387 "LAST_DIRECTORY"), new String[] { "fc" },
\r
388 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
389 chooser.setFileView(new jalview.io.JalviewFileView());
\r
390 chooser.setDialogTitle("Load Feature Colours");
\r
391 chooser.setToolTipText("Load");
\r
393 int value = chooser.showOpenDialog(this);
\r
395 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
397 File file = chooser.getSelectedFile();
\r
401 InputStreamReader in = new InputStreamReader(new FileInputStream(
\r
404 jalview.binding.JalviewUserColours jucs = new jalview.binding.
\r
405 JalviewUserColours();
\r
406 jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);
\r
409 for (int i = 0; i < jucs.getColourCount(); i++)
\r
411 fr.setColour( jucs.getColour(i).getName(),
\r
412 new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));
\r
418 catch (Exception ex)
\r
420 System.out.println("Error loading User ColourFile\n" + ex);
\r
427 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
428 "LAST_DIRECTORY"), new String[] { "fc" },
\r
429 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
430 chooser.setFileView(new jalview.io.JalviewFileView());
\r
431 chooser.setDialogTitle("Save Feature Colour Scheme");
\r
432 chooser.setToolTipText("Save");
\r
434 int value = chooser.showSaveDialog(this);
\r
436 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
438 String choice = chooser.getSelectedFile().getPath();
\r
439 jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();
\r
440 ucs.setSchemeName("Sequence Features");
\r
443 PrintWriter out = new PrintWriter(new OutputStreamWriter(
\r
444 new FileOutputStream(choice), "UTF-8"));
\r
446 Enumeration e = fr.featureColours.keys();
\r
447 while(e.hasMoreElements())
\r
449 jalview.binding.Colour col = new jalview.binding.Colour();
\r
450 col.setName(e.nextElement().toString());
\r
451 col.setRGB(jalview.util.Format.getHexString(
\r
452 fr.getColour(col.getName())));
\r
453 ucs.addColour(col);
\r
459 catch (Exception ex)
\r
461 ex.printStackTrace();
\r
466 public void invertSelection()
\r
468 for(int i=0; i<table.getRowCount(); i++)
\r
470 Boolean value = (Boolean)table.getValueAt(i,2);
\r
473 new Boolean(!value.booleanValue()),
\r
479 public void updateFeatureRenderer(Object [][] data)
\r
481 fr.setFeaturePriority( data );
\r
484 if(ap.overviewPanel!=null)
\r
485 ap.overviewPanel.updateOverviewImage();
\r
488 int selectedRow =-1;
\r
491 /////////////////////////////////////////////////////////////////////////
\r
492 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
\r
493 /////////////////////////////////////////////////////////////////////////
\r
494 class FeatureTableModel
\r
495 extends AbstractTableModel
\r
497 FeatureTableModel(Object[][] data)
\r
502 private String[] columnNames = {"Feature Type", "Colour","Display"};
\r
503 private Object[][] data;
\r
505 public Object[][] getData()
\r
510 public void setData(Object[][] data)
\r
515 public int getColumnCount() {
\r
516 return columnNames.length;
\r
519 public Object[] getRow(int row)
\r
524 public int getRowCount() {
\r
525 return data.length;
\r
528 public String getColumnName(int col) {
\r
529 return columnNames[col];
\r
532 public Object getValueAt(int row, int col) {
\r
533 return data[row][col];
\r
536 public Class getColumnClass(int c) {
\r
537 return getValueAt(0, c).getClass();
\r
540 public boolean isCellEditable(int row, int col) {
\r
541 return col==0 ? false:true;
\r
544 public void setValueAt(Object value, int row, int col) {
\r
545 data[row][col] = value;
\r
546 fireTableCellUpdated(row, col);
\r
547 updateFeatureRenderer(data);
\r
551 class ColorRenderer extends JLabel
\r
552 implements TableCellRenderer {
\r
553 javax.swing.border.Border unselectedBorder = null;
\r
554 javax.swing.border.Border selectedBorder = null;
\r
556 public ColorRenderer() {
\r
557 setOpaque(true); //MUST do this for background to show up.
\r
560 public Component getTableCellRendererComponent(
\r
561 JTable table, Object color,
\r
562 boolean isSelected, boolean hasFocus,
\r
563 int row, int column) {
\r
564 Color newColor = (Color)color;
\r
565 setBackground(newColor);
\r
567 if (selectedBorder == null) {
\r
568 selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
569 table.getSelectionBackground());
\r
571 setBorder(selectedBorder);
\r
573 if (unselectedBorder == null) {
\r
574 unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
575 table.getBackground());
\r
577 setBorder(unselectedBorder);
\r
580 setToolTipText("RGB value: " + newColor.getRed() + ", "
\r
581 + newColor.getGreen() + ", "
\r
582 + newColor.getBlue());
\r
588 class ColorEditor extends AbstractCellEditor
\r
589 implements TableCellEditor,
\r
591 Color currentColor;
\r
593 JColorChooser colorChooser;
\r
595 protected static final String EDIT = "edit";
\r
597 public ColorEditor() {
\r
598 //Set up the editor (from the table's point of view),
\r
599 //which is a button.
\r
600 //This button brings up the color chooser dialog,
\r
601 //which is the editor from the user's point of view.
\r
602 button = new JButton();
\r
603 button.setActionCommand(EDIT);
\r
604 button.addActionListener(this);
\r
605 button.setBorderPainted(false);
\r
606 //Set up the dialog that the button brings up.
\r
607 colorChooser = new JColorChooser();
\r
608 dialog = JColorChooser.createDialog(button,
\r
609 "Select new Colour",
\r
612 this, //OK button handler
\r
613 null); //no CANCEL button handler
\r
617 * Handles events from the editor button and from
\r
618 * the dialog's OK button.
\r
620 public void actionPerformed(ActionEvent e) {
\r
622 if (EDIT.equals(e.getActionCommand())) {
\r
623 //The user has clicked the cell, so
\r
624 //bring up the dialog.
\r
625 button.setBackground(currentColor);
\r
626 colorChooser.setColor(currentColor);
\r
627 dialog.setVisible(true);
\r
629 //Make the renderer reappear.
\r
630 fireEditingStopped();
\r
632 } else { //User pressed dialog's "OK" button.
\r
633 currentColor = colorChooser.getColor();
\r
637 //Implement the one CellEditor method that AbstractCellEditor doesn't.
\r
638 public Object getCellEditorValue() {
\r
639 return currentColor;
\r
642 //Implement the one method defined by TableCellEditor.
\r
643 public Component getTableCellEditorComponent(JTable table,
\r
645 boolean isSelected,
\r
648 currentColor = (Color)value;
\r