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
58 final JSlider transparency = new JSlider(0, 70, 0);
\r
59 transparency.addChangeListener(new ChangeListener()
\r
61 public void stateChanged(ChangeEvent evt)
\r
63 fr.setTransparency( (float) (100 - transparency.getValue()) / 100f);
\r
68 JPanel transPanel = new JPanel(new FlowLayout());
\r
69 transPanel.add(new JLabel("Transparency"));
\r
70 transPanel.add(transparency);
\r
72 //////////////////////////////////////////////
\r
73 //We're going to need those OK cancel buttons
\r
74 JPanel buttonPanel = new JPanel(new FlowLayout());
\r
75 JButton button = new JButton("OK");
\r
76 button.addActionListener(new ActionListener()
\r
78 public void actionPerformed(ActionEvent evt)
\r
82 frame.setClosed(true);
\r
84 catch (Exception exe)
\r
88 buttonPanel.add(button);
\r
89 button = new JButton("Cancel");
\r
90 button.addActionListener(new ActionListener()
\r
92 public void actionPerformed(ActionEvent evt)
\r
96 updateFeatureRenderer(originalData);
\r
97 frame.setClosed(true);
\r
99 catch (Exception exe)
\r
103 buttonPanel.add(button);
\r
105 button = new JButton("Load Colours");
\r
106 button.addActionListener(new ActionListener()
\r
108 public void actionPerformed(ActionEvent evt)
\r
113 buttonPanel.add(button);
\r
114 button = new JButton("Save Colours");
\r
115 button.addActionListener(new ActionListener()
\r
117 public void actionPerformed(ActionEvent evt)
\r
122 buttonPanel.add(button);
\r
124 this.setLayout(new BorderLayout());
\r
125 JPanel bigPanel = new JPanel(new BorderLayout());
\r
126 bigPanel.add(transPanel, BorderLayout.SOUTH);
\r
127 bigPanel.add(scrollPane, BorderLayout.CENTER);
\r
128 if(groupPanel!=null)
\r
130 groupPanel.setLayout(
\r
131 new GridLayout(fr.featureGroups.size() / 4 + 1, 4));
\r
133 groupPanel.validate();
\r
134 bigPanel.add(groupPanel, BorderLayout.NORTH);
\r
136 add(bigPanel, BorderLayout.CENTER);
\r
137 add(buttonPanel, BorderLayout.SOUTH);
\r
142 void setTableData()
\r
144 alignmentHasFeatures = false;
\r
146 if (fr.featureGroups == null)
\r
147 fr.featureGroups = new Hashtable();
\r
149 Vector allFeatures = new Vector();
\r
150 Vector allGroups = new Vector();
\r
151 SequenceFeature[] tmpfeatures;
\r
154 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
156 if (av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
159 alignmentHasFeatures = true;
\r
161 tmpfeatures = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
163 while (index < tmpfeatures.length)
\r
165 if(tmpfeatures[index].getFeatureGroup()!=null)
\r
167 group = tmpfeatures[index].featureGroup;
\r
168 if(!allGroups.contains(group))
\r
170 allGroups.addElement(group);
\r
172 boolean visible = true;
\r
173 if (fr.featureGroups.containsKey(group))
\r
175 visible = ( (Boolean) fr.featureGroups.get(group)).booleanValue();
\r
178 fr.featureGroups.put(group, new Boolean(visible));
\r
180 if (groupPanel == null)
\r
182 groupPanel = new JPanel();
\r
185 final JCheckBox check = new JCheckBox(group, visible);
\r
186 check.setFont(new Font("Serif", Font.BOLD, 12));
\r
187 check.addItemListener(new ItemListener()
\r
189 public void itemStateChanged(ItemEvent evt)
\r
191 fr.featureGroups.put(check.getText(),
\r
192 new Boolean(check.isSelected()));
\r
193 ap.seqPanel.seqCanvas.repaint();
\r
194 if (ap.overviewPanel != null)
\r
195 ap.overviewPanel.updateOverviewImage();
\r
200 groupPanel.add(check);
\r
206 if (!allFeatures.contains(tmpfeatures[index].getType()))
\r
208 allFeatures.addElement(tmpfeatures[index].getType());
\r
215 if(!alignmentHasFeatures)
\r
218 { frame.setClosed(true); }
\r
219 catch (Exception ex){}
\r
221 JOptionPane.showInternalMessageDialog(
\r
222 Desktop.desktop, "No features have been added to this alignment!",
\r
223 "No Sequence Features", JOptionPane.WARNING_MESSAGE);
\r
231 void resetTable(boolean groupsChanged)
\r
233 SequenceFeature [] tmpfeatures;
\r
234 String group=null, type;
\r
235 Vector visibleChecks = new Vector();
\r
237 //Find out which features should be visible depending on which groups
\r
238 //are selected / deselected
\r
239 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
241 if (av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
244 tmpfeatures = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
246 while (index < tmpfeatures.length)
\r
248 group = tmpfeatures[index].featureGroup;
\r
250 if (group==null || fr.featureGroups.get(group)==null ||
\r
251 ((Boolean) fr.featureGroups.get(group)).booleanValue())
\r
253 type = tmpfeatures[index].getType();
\r
254 if(!visibleChecks.contains(type) )
\r
256 visibleChecks.addElement(type);
\r
263 int fSize = visibleChecks.size();
\r
264 Object [][] data = new Object[fSize][3];
\r
267 if(fr.renderOrder!=null)
\r
269 //First add the checks in the previous render order,
\r
270 //in case the window has been closed and reopened
\r
271 for(int ro=fr.renderOrder.length-1; ro>-1; ro--)
\r
273 type = fr.renderOrder[ro];
\r
275 if(!visibleChecks.contains(type))
\r
278 data[dataIndex][0] = type;
\r
279 data[dataIndex][1] = fr.getColour(type);
\r
280 data[dataIndex][2] = new Boolean(av.featuresDisplayed.containsKey(type));
\r
282 visibleChecks.removeElement(type);
\r
286 fSize = visibleChecks.size();
\r
287 for(int i=0; i<fSize; i++)
\r
289 //These must be extra features belonging to the group
\r
290 //which was just selected
\r
291 type = visibleChecks.elementAt(i).toString();
\r
292 data[dataIndex][0] = type;
\r
293 data[dataIndex][1] = fr.getColour(type);
\r
294 data[dataIndex][2] = new Boolean(true);
\r
298 if(originalData==null)
\r
300 originalData = new Object[data.length][3];
\r
301 System.arraycopy(data,0,originalData,0,data.length);
\r
304 table = new JTable(new FeatureTableModel(data));
\r
305 scrollPane.setViewportView(table);
\r
306 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
\r
307 table.setFont(new Font("Verdana", Font.PLAIN, 12));
\r
308 table.setDefaultRenderer(Color.class,
\r
309 new ColorRenderer());
\r
311 table.setDefaultEditor(Color.class,
\r
312 new ColorEditor());
\r
314 table.getColumnModel().getColumn(0).setPreferredWidth(200);
\r
316 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
\r
318 table.addMouseListener(new MouseAdapter()
\r
320 public void mousePressed(MouseEvent evt)
\r
322 selectedRow = table.rowAtPoint(evt.getPoint());
\r
326 table.addMouseMotionListener(new MouseMotionAdapter()
\r
328 public void mouseDragged(MouseEvent evt)
\r
330 int newRow = table.rowAtPoint(evt.getPoint());
\r
331 if(newRow!=selectedRow
\r
335 Object[] temp = new Object[3];
\r
336 temp[0] = table.getValueAt(selectedRow, 0);
\r
337 temp[1] = table.getValueAt(selectedRow, 1);
\r
338 temp[2] = table.getValueAt(selectedRow, 2);
\r
340 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
\r
341 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
\r
342 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
\r
344 table.setValueAt(temp[0], newRow, 0);
\r
345 table.setValueAt(temp[1], newRow, 1);
\r
346 table.setValueAt(temp[2], newRow, 2);
\r
348 selectedRow = newRow;
\r
353 updateFeatureRenderer(data);
\r
359 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
360 "LAST_DIRECTORY"), new String[] { "fc" },
\r
361 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
362 chooser.setFileView(new jalview.io.JalviewFileView());
\r
363 chooser.setDialogTitle("Load Feature Colours");
\r
364 chooser.setToolTipText("Load");
\r
366 int value = chooser.showOpenDialog(this);
\r
368 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
370 File file = chooser.getSelectedFile();
\r
374 InputStreamReader in = new InputStreamReader(new FileInputStream(
\r
377 jalview.binding.JalviewUserColours jucs = new jalview.binding.
\r
378 JalviewUserColours();
\r
379 jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);
\r
382 for (int i = 0; i < jucs.getColourCount(); i++)
\r
384 fr.setColour( jucs.getColour(i).getName(),
\r
385 new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));
\r
391 catch (Exception ex)
\r
393 System.out.println("Error loading User ColourFile\n" + ex);
\r
400 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
401 "LAST_DIRECTORY"), new String[] { "fc" },
\r
402 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
403 chooser.setFileView(new jalview.io.JalviewFileView());
\r
404 chooser.setDialogTitle("Save Feature Colour Scheme");
\r
405 chooser.setToolTipText("Save");
\r
407 int value = chooser.showSaveDialog(this);
\r
409 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
411 String choice = chooser.getSelectedFile().getPath();
\r
412 jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();
\r
413 ucs.setSchemeName("Sequence Features");
\r
416 PrintWriter out = new PrintWriter(new OutputStreamWriter(
\r
417 new FileOutputStream(choice), "UTF-8"));
\r
419 Enumeration e = fr.featureColours.keys();
\r
420 while(e.hasMoreElements())
\r
424 jalview.binding.Colour col = new jalview.binding.Colour();
\r
425 col.setName(e.nextElement().toString());
\r
426 col.setRGB(jalview.util.Format.getHexString(
\r
427 fr.getColour(col.getName())));
\r
428 ucs.addColour(col);
\r
434 catch (Exception ex)
\r
436 ex.printStackTrace();
\r
442 public void updateFeatureRenderer(Object [][] data)
\r
444 fr.setFeaturePriority( data );
\r
447 if(ap.overviewPanel!=null)
\r
448 ap.overviewPanel.updateOverviewImage();
\r
451 int selectedRow =-1;
\r
454 /////////////////////////////////////////////////////////////////////////
\r
455 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
\r
456 /////////////////////////////////////////////////////////////////////////
\r
457 class FeatureTableModel
\r
458 extends AbstractTableModel
\r
460 FeatureTableModel(Object[][] data)
\r
465 private String[] columnNames = {"Feature Type", "Colour","Display"};
\r
466 private Object[][] data;
\r
468 public Object[][] getData()
\r
473 public void setData(Object[][] data)
\r
478 public int getColumnCount() {
\r
479 return columnNames.length;
\r
482 public Object[] getRow(int row)
\r
487 public int getRowCount() {
\r
488 return data.length;
\r
491 public String getColumnName(int col) {
\r
492 return columnNames[col];
\r
495 public Object getValueAt(int row, int col) {
\r
496 return data[row][col];
\r
499 public Class getColumnClass(int c) {
\r
500 return getValueAt(0, c).getClass();
\r
503 public boolean isCellEditable(int row, int col) {
\r
504 return col==0 ? false:true;
\r
507 public void setValueAt(Object value, int row, int col) {
\r
508 data[row][col] = value;
\r
509 fireTableCellUpdated(row, col);
\r
510 updateFeatureRenderer(data);
\r
514 class ColorRenderer extends JLabel
\r
515 implements TableCellRenderer {
\r
516 javax.swing.border.Border unselectedBorder = null;
\r
517 javax.swing.border.Border selectedBorder = null;
\r
519 public ColorRenderer() {
\r
520 setOpaque(true); //MUST do this for background to show up.
\r
523 public Component getTableCellRendererComponent(
\r
524 JTable table, Object color,
\r
525 boolean isSelected, boolean hasFocus,
\r
526 int row, int column) {
\r
527 Color newColor = (Color)color;
\r
528 setBackground(newColor);
\r
530 if (selectedBorder == null) {
\r
531 selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
532 table.getSelectionBackground());
\r
534 setBorder(selectedBorder);
\r
536 if (unselectedBorder == null) {
\r
537 unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
538 table.getBackground());
\r
540 setBorder(unselectedBorder);
\r
543 setToolTipText("RGB value: " + newColor.getRed() + ", "
\r
544 + newColor.getGreen() + ", "
\r
545 + newColor.getBlue());
\r
551 class ColorEditor extends AbstractCellEditor
\r
552 implements TableCellEditor,
\r
554 Color currentColor;
\r
556 JColorChooser colorChooser;
\r
558 protected static final String EDIT = "edit";
\r
560 public ColorEditor() {
\r
561 //Set up the editor (from the table's point of view),
\r
562 //which is a button.
\r
563 //This button brings up the color chooser dialog,
\r
564 //which is the editor from the user's point of view.
\r
565 button = new JButton();
\r
566 button.setActionCommand(EDIT);
\r
567 button.addActionListener(this);
\r
568 button.setBorderPainted(false);
\r
569 //Set up the dialog that the button brings up.
\r
570 colorChooser = new JColorChooser();
\r
571 dialog = JColorChooser.createDialog(button,
\r
572 "Select new Colour",
\r
575 this, //OK button handler
\r
576 null); //no CANCEL button handler
\r
580 * Handles events from the editor button and from
\r
581 * the dialog's OK button.
\r
583 public void actionPerformed(ActionEvent e) {
\r
585 if (EDIT.equals(e.getActionCommand())) {
\r
586 //The user has clicked the cell, so
\r
587 //bring up the dialog.
\r
588 button.setBackground(currentColor);
\r
589 colorChooser.setColor(currentColor);
\r
590 dialog.setVisible(true);
\r
592 //Make the renderer reappear.
\r
593 fireEditingStopped();
\r
595 } else { //User pressed dialog's "OK" button.
\r
596 currentColor = colorChooser.getColor();
\r
600 //Implement the one CellEditor method that AbstractCellEditor doesn't.
\r
601 public Object getCellEditorValue() {
\r
602 return currentColor;
\r
605 //Implement the one method defined by TableCellEditor.
\r
606 public Component getTableCellEditorComponent(JTable table,
\r
608 boolean isSelected,
\r
611 currentColor = (Color)value;
\r