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, 0);
\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
73 //////////////////////////////////////////////
\r
74 //We're going to need those OK cancel buttons
\r
75 JPanel buttonPanel = new JPanel(new FlowLayout());
\r
76 JButton button = new JButton("OK");
\r
77 button.addActionListener(new ActionListener()
\r
79 public void actionPerformed(ActionEvent evt)
\r
83 frame.setClosed(true);
\r
85 catch (Exception exe)
\r
89 buttonPanel.add(button);
\r
90 button = new JButton("Cancel");
\r
91 button.addActionListener(new ActionListener()
\r
93 public void actionPerformed(ActionEvent evt)
\r
97 updateFeatureRenderer(originalData);
\r
98 frame.setClosed(true);
\r
100 catch (Exception exe)
\r
104 buttonPanel.add(button);
\r
106 button = new JButton("Load Colours");
\r
107 button.addActionListener(new ActionListener()
\r
109 public void actionPerformed(ActionEvent evt)
\r
114 buttonPanel.add(button);
\r
115 button = new JButton("Save Colours");
\r
116 button.addActionListener(new ActionListener()
\r
118 public void actionPerformed(ActionEvent evt)
\r
123 buttonPanel.add(button);
\r
125 this.setLayout(new BorderLayout());
\r
126 JPanel bigPanel = new JPanel(new BorderLayout());
\r
127 bigPanel.add(transPanel, BorderLayout.SOUTH);
\r
128 bigPanel.add(scrollPane, BorderLayout.CENTER);
\r
129 if(groupPanel!=null)
\r
131 groupPanel.setLayout(
\r
132 new GridLayout(fr.featureGroups.size() / 4 + 1, 4));
\r
134 groupPanel.validate();
\r
135 bigPanel.add(groupPanel, BorderLayout.NORTH);
\r
137 add(bigPanel, BorderLayout.CENTER);
\r
138 add(buttonPanel, BorderLayout.SOUTH);
\r
143 void setTableData()
\r
145 alignmentHasFeatures = false;
\r
147 if (fr.featureGroups == null)
\r
148 fr.featureGroups = new Hashtable();
\r
150 Vector allFeatures = new Vector();
\r
151 Vector allGroups = new Vector();
\r
152 SequenceFeature[] tmpfeatures;
\r
155 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
157 if (av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
160 alignmentHasFeatures = true;
\r
162 tmpfeatures = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
164 while (index < tmpfeatures.length)
\r
166 if(tmpfeatures[index].getFeatureGroup()!=null)
\r
168 group = tmpfeatures[index].featureGroup;
\r
169 if(!allGroups.contains(group))
\r
171 allGroups.addElement(group);
\r
173 boolean visible = true;
\r
174 if (fr.featureGroups.containsKey(group))
\r
176 visible = ( (Boolean) fr.featureGroups.get(group)).booleanValue();
\r
179 fr.featureGroups.put(group, new Boolean(visible));
\r
181 if (groupPanel == null)
\r
183 groupPanel = new JPanel();
\r
186 final JCheckBox check = new JCheckBox(group, visible);
\r
187 check.setFont(new Font("Serif", Font.BOLD, 12));
\r
188 check.addItemListener(new ItemListener()
\r
190 public void itemStateChanged(ItemEvent evt)
\r
192 fr.featureGroups.put(check.getText(),
\r
193 new Boolean(check.isSelected()));
\r
194 ap.seqPanel.seqCanvas.repaint();
\r
195 if (ap.overviewPanel != null)
\r
196 ap.overviewPanel.updateOverviewImage();
\r
201 groupPanel.add(check);
\r
207 if (!allFeatures.contains(tmpfeatures[index].getType()))
\r
209 allFeatures.addElement(tmpfeatures[index].getType());
\r
216 if(!alignmentHasFeatures)
\r
219 { frame.setClosed(true); }
\r
220 catch (Exception ex){}
\r
222 JOptionPane.showInternalMessageDialog(
\r
223 Desktop.desktop, "No features have been added to this alignment!",
\r
224 "No Sequence Features", JOptionPane.WARNING_MESSAGE);
\r
232 void resetTable(boolean groupsChanged)
\r
234 SequenceFeature [] tmpfeatures;
\r
235 String group=null, type;
\r
236 Vector visibleChecks = new Vector();
\r
238 //Find out which features should be visible depending on which groups
\r
239 //are selected / deselected
\r
240 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
242 if (av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
245 tmpfeatures = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
247 while (index < tmpfeatures.length)
\r
249 group = tmpfeatures[index].featureGroup;
\r
251 if (group==null || fr.featureGroups.get(group)==null ||
\r
252 ((Boolean) fr.featureGroups.get(group)).booleanValue())
\r
254 type = tmpfeatures[index].getType();
\r
255 if(!visibleChecks.contains(type) )
\r
257 visibleChecks.addElement(type);
\r
264 int fSize = visibleChecks.size();
\r
265 Object [][] data = new Object[fSize][3];
\r
268 if(fr.renderOrder!=null)
\r
270 //First add the checks in the previous render order,
\r
271 //in case the window has been closed and reopened
\r
272 for(int ro=fr.renderOrder.length-1; ro>-1; ro--)
\r
274 type = fr.renderOrder[ro];
\r
276 if(!visibleChecks.contains(type))
\r
279 data[dataIndex][0] = type;
\r
280 data[dataIndex][1] = fr.getColour(type);
\r
281 data[dataIndex][2] = new Boolean(av.featuresDisplayed.containsKey(type));
\r
283 visibleChecks.removeElement(type);
\r
287 fSize = visibleChecks.size();
\r
288 for(int i=0; i<fSize; i++)
\r
290 //These must be extra features belonging to the group
\r
291 //which was just selected
\r
292 type = visibleChecks.elementAt(i).toString();
\r
293 data[dataIndex][0] = type;
\r
294 data[dataIndex][1] = fr.getColour(type);
\r
295 data[dataIndex][2] = new Boolean(true);
\r
299 if(originalData==null)
\r
301 originalData = new Object[data.length][3];
\r
302 System.arraycopy(data,0,originalData,0,data.length);
\r
305 table = new JTable(new FeatureTableModel(data));
\r
306 scrollPane.setViewportView(table);
\r
307 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
\r
308 table.setFont(new Font("Verdana", Font.PLAIN, 12));
\r
309 table.setDefaultRenderer(Color.class,
\r
310 new ColorRenderer());
\r
312 table.setDefaultEditor(Color.class,
\r
313 new ColorEditor());
\r
315 table.getColumnModel().getColumn(0).setPreferredWidth(200);
\r
317 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
\r
319 table.addMouseListener(new MouseAdapter()
\r
321 public void mousePressed(MouseEvent evt)
\r
323 selectedRow = table.rowAtPoint(evt.getPoint());
\r
327 table.addMouseMotionListener(new MouseMotionAdapter()
\r
329 public void mouseDragged(MouseEvent evt)
\r
331 int newRow = table.rowAtPoint(evt.getPoint());
\r
332 if(newRow!=selectedRow
\r
336 Object[] temp = new Object[3];
\r
337 temp[0] = table.getValueAt(selectedRow, 0);
\r
338 temp[1] = table.getValueAt(selectedRow, 1);
\r
339 temp[2] = table.getValueAt(selectedRow, 2);
\r
341 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
\r
342 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
\r
343 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
\r
345 table.setValueAt(temp[0], newRow, 0);
\r
346 table.setValueAt(temp[1], newRow, 1);
\r
347 table.setValueAt(temp[2], newRow, 2);
\r
349 selectedRow = newRow;
\r
354 updateFeatureRenderer(data);
\r
360 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
361 "LAST_DIRECTORY"), new String[] { "fc" },
\r
362 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
363 chooser.setFileView(new jalview.io.JalviewFileView());
\r
364 chooser.setDialogTitle("Load Feature Colours");
\r
365 chooser.setToolTipText("Load");
\r
367 int value = chooser.showOpenDialog(this);
\r
369 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
371 File file = chooser.getSelectedFile();
\r
375 InputStreamReader in = new InputStreamReader(new FileInputStream(
\r
378 jalview.binding.JalviewUserColours jucs = new jalview.binding.
\r
379 JalviewUserColours();
\r
380 jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);
\r
383 for (int i = 0; i < jucs.getColourCount(); i++)
\r
385 fr.setColour( jucs.getColour(i).getName(),
\r
386 new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));
\r
392 catch (Exception ex)
\r
394 System.out.println("Error loading User ColourFile\n" + ex);
\r
401 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
402 "LAST_DIRECTORY"), new String[] { "fc" },
\r
403 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
404 chooser.setFileView(new jalview.io.JalviewFileView());
\r
405 chooser.setDialogTitle("Save Feature Colour Scheme");
\r
406 chooser.setToolTipText("Save");
\r
408 int value = chooser.showSaveDialog(this);
\r
410 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
412 String choice = chooser.getSelectedFile().getPath();
\r
413 jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();
\r
414 ucs.setSchemeName("Sequence Features");
\r
417 PrintWriter out = new PrintWriter(new OutputStreamWriter(
\r
418 new FileOutputStream(choice), "UTF-8"));
\r
420 Enumeration e = fr.featureColours.keys();
\r
421 while(e.hasMoreElements())
\r
425 jalview.binding.Colour col = new jalview.binding.Colour();
\r
426 col.setName(e.nextElement().toString());
\r
427 col.setRGB(jalview.util.Format.getHexString(
\r
428 fr.getColour(col.getName())));
\r
429 ucs.addColour(col);
\r
435 catch (Exception ex)
\r
437 ex.printStackTrace();
\r
443 public void updateFeatureRenderer(Object [][] data)
\r
445 fr.setFeaturePriority( data );
\r
448 if(ap.overviewPanel!=null)
\r
449 ap.overviewPanel.updateOverviewImage();
\r
452 int selectedRow =-1;
\r
455 /////////////////////////////////////////////////////////////////////////
\r
456 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
\r
457 /////////////////////////////////////////////////////////////////////////
\r
458 class FeatureTableModel
\r
459 extends AbstractTableModel
\r
461 FeatureTableModel(Object[][] data)
\r
466 private String[] columnNames = {"Feature Type", "Colour","Display"};
\r
467 private Object[][] data;
\r
469 public Object[][] getData()
\r
474 public void setData(Object[][] data)
\r
479 public int getColumnCount() {
\r
480 return columnNames.length;
\r
483 public Object[] getRow(int row)
\r
488 public int getRowCount() {
\r
489 return data.length;
\r
492 public String getColumnName(int col) {
\r
493 return columnNames[col];
\r
496 public Object getValueAt(int row, int col) {
\r
497 return data[row][col];
\r
500 public Class getColumnClass(int c) {
\r
501 return getValueAt(0, c).getClass();
\r
504 public boolean isCellEditable(int row, int col) {
\r
505 return col==0 ? false:true;
\r
508 public void setValueAt(Object value, int row, int col) {
\r
509 data[row][col] = value;
\r
510 fireTableCellUpdated(row, col);
\r
511 updateFeatureRenderer(data);
\r
515 class ColorRenderer extends JLabel
\r
516 implements TableCellRenderer {
\r
517 javax.swing.border.Border unselectedBorder = null;
\r
518 javax.swing.border.Border selectedBorder = null;
\r
520 public ColorRenderer() {
\r
521 setOpaque(true); //MUST do this for background to show up.
\r
524 public Component getTableCellRendererComponent(
\r
525 JTable table, Object color,
\r
526 boolean isSelected, boolean hasFocus,
\r
527 int row, int column) {
\r
528 Color newColor = (Color)color;
\r
529 setBackground(newColor);
\r
531 if (selectedBorder == null) {
\r
532 selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
533 table.getSelectionBackground());
\r
535 setBorder(selectedBorder);
\r
537 if (unselectedBorder == null) {
\r
538 unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
539 table.getBackground());
\r
541 setBorder(unselectedBorder);
\r
544 setToolTipText("RGB value: " + newColor.getRed() + ", "
\r
545 + newColor.getGreen() + ", "
\r
546 + newColor.getBlue());
\r
552 class ColorEditor extends AbstractCellEditor
\r
553 implements TableCellEditor,
\r
555 Color currentColor;
\r
557 JColorChooser colorChooser;
\r
559 protected static final String EDIT = "edit";
\r
561 public ColorEditor() {
\r
562 //Set up the editor (from the table's point of view),
\r
563 //which is a button.
\r
564 //This button brings up the color chooser dialog,
\r
565 //which is the editor from the user's point of view.
\r
566 button = new JButton();
\r
567 button.setActionCommand(EDIT);
\r
568 button.addActionListener(this);
\r
569 button.setBorderPainted(false);
\r
570 //Set up the dialog that the button brings up.
\r
571 colorChooser = new JColorChooser();
\r
572 dialog = JColorChooser.createDialog(button,
\r
573 "Select new Colour",
\r
576 this, //OK button handler
\r
577 null); //no CANCEL button handler
\r
581 * Handles events from the editor button and from
\r
582 * the dialog's OK button.
\r
584 public void actionPerformed(ActionEvent e) {
\r
586 if (EDIT.equals(e.getActionCommand())) {
\r
587 //The user has clicked the cell, so
\r
588 //bring up the dialog.
\r
589 button.setBackground(currentColor);
\r
590 colorChooser.setColor(currentColor);
\r
591 dialog.setVisible(true);
\r
593 //Make the renderer reappear.
\r
594 fireEditingStopped();
\r
596 } else { //User pressed dialog's "OK" button.
\r
597 currentColor = colorChooser.getColor();
\r
601 //Implement the one CellEditor method that AbstractCellEditor doesn't.
\r
602 public Object getCellEditorValue() {
\r
603 return currentColor;
\r
606 //Implement the one method defined by TableCellEditor.
\r
607 public Component getTableCellEditorComponent(JTable table,
\r
609 boolean isSelected,
\r
612 currentColor = (Color)value;
\r