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
173 while (index < tmpfeatures.length)
\r
175 if(tmpfeatures[index].getFeatureGroup()!=null)
\r
177 group = tmpfeatures[index].featureGroup;
\r
178 if(!allGroups.contains(group))
\r
180 allGroups.addElement(group);
\r
182 boolean visible = true;
\r
183 if (fr.featureGroups.containsKey(group))
\r
185 visible = ( (Boolean) fr.featureGroups.get(group)).booleanValue();
\r
188 fr.featureGroups.put(group, new Boolean(visible));
\r
190 if (groupPanel == null)
\r
192 groupPanel = new JPanel();
\r
195 final JCheckBox check = new JCheckBox(group, visible);
\r
196 check.setFont(new Font("Serif", Font.BOLD, 12));
\r
197 check.addItemListener(new ItemListener()
\r
199 public void itemStateChanged(ItemEvent evt)
\r
201 fr.featureGroups.put(check.getText(),
\r
202 new Boolean(check.isSelected()));
\r
203 ap.seqPanel.seqCanvas.repaint();
\r
204 if (ap.overviewPanel != null)
\r
205 ap.overviewPanel.updateOverviewImage();
\r
210 groupPanel.add(check);
\r
216 if (!allFeatures.contains(tmpfeatures[index].getType()))
\r
218 allFeatures.addElement(tmpfeatures[index].getType());
\r
225 if(!alignmentHasFeatures)
\r
228 { frame.setClosed(true); }
\r
229 catch (Exception ex){}
\r
231 JOptionPane.showInternalMessageDialog(
\r
232 Desktop.desktop, "No features have been added to this alignment!",
\r
233 "No Sequence Features", JOptionPane.WARNING_MESSAGE);
\r
241 void resetTable(boolean groupsChanged)
\r
243 SequenceFeature [] tmpfeatures;
\r
244 String group=null, type;
\r
245 Vector visibleChecks = new Vector();
\r
247 //Find out which features should be visible depending on which groups
\r
248 //are selected / deselected
\r
249 for (int i = 0; i < av.alignment.getHeight(); i++)
\r
251 if (av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures() == null)
\r
254 tmpfeatures = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();
\r
256 while (index < tmpfeatures.length)
\r
258 group = tmpfeatures[index].featureGroup;
\r
260 if (group==null || fr.featureGroups.get(group)==null ||
\r
261 ((Boolean) fr.featureGroups.get(group)).booleanValue())
\r
263 type = tmpfeatures[index].getType();
\r
264 if(!visibleChecks.contains(type) )
\r
266 visibleChecks.addElement(type);
\r
273 int fSize = visibleChecks.size();
\r
274 Object [][] data = new Object[fSize][3];
\r
277 if(fr.renderOrder!=null)
\r
279 //First add the checks in the previous render order,
\r
280 //in case the window has been closed and reopened
\r
281 for(int ro=fr.renderOrder.length-1; ro>-1; ro--)
\r
283 type = fr.renderOrder[ro];
\r
285 if(!visibleChecks.contains(type))
\r
288 data[dataIndex][0] = type;
\r
289 data[dataIndex][1] = fr.getColour(type);
\r
290 data[dataIndex][2] = new Boolean(av.featuresDisplayed.containsKey(type));
\r
292 visibleChecks.removeElement(type);
\r
296 fSize = visibleChecks.size();
\r
297 for(int i=0; i<fSize; i++)
\r
299 //These must be extra features belonging to the group
\r
300 //which was just selected
\r
301 type = visibleChecks.elementAt(i).toString();
\r
302 data[dataIndex][0] = type;
\r
303 data[dataIndex][1] = fr.getColour(type);
\r
304 data[dataIndex][2] = new Boolean(true);
\r
308 if(originalData==null)
\r
310 originalData = new Object[data.length][3];
\r
311 System.arraycopy(data,0,originalData,0,data.length);
\r
314 table = new JTable(new FeatureTableModel(data));
\r
315 scrollPane.setViewportView(table);
\r
316 table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
\r
317 table.setFont(new Font("Verdana", Font.PLAIN, 12));
\r
318 table.setDefaultRenderer(Color.class,
\r
319 new ColorRenderer());
\r
321 table.setDefaultEditor(Color.class,
\r
322 new ColorEditor());
\r
324 table.getColumnModel().getColumn(0).setPreferredWidth(200);
\r
326 table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
\r
328 table.addMouseListener(new MouseAdapter()
\r
330 public void mousePressed(MouseEvent evt)
\r
332 selectedRow = table.rowAtPoint(evt.getPoint());
\r
336 table.addMouseMotionListener(new MouseMotionAdapter()
\r
338 public void mouseDragged(MouseEvent evt)
\r
340 int newRow = table.rowAtPoint(evt.getPoint());
\r
341 if(newRow!=selectedRow
\r
345 Object[] temp = new Object[3];
\r
346 temp[0] = table.getValueAt(selectedRow, 0);
\r
347 temp[1] = table.getValueAt(selectedRow, 1);
\r
348 temp[2] = table.getValueAt(selectedRow, 2);
\r
350 table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);
\r
351 table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);
\r
352 table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);
\r
354 table.setValueAt(temp[0], newRow, 0);
\r
355 table.setValueAt(temp[1], newRow, 1);
\r
356 table.setValueAt(temp[2], newRow, 2);
\r
358 selectedRow = newRow;
\r
363 updateFeatureRenderer(data);
\r
369 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
370 "LAST_DIRECTORY"), new String[] { "fc" },
\r
371 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
372 chooser.setFileView(new jalview.io.JalviewFileView());
\r
373 chooser.setDialogTitle("Load Feature Colours");
\r
374 chooser.setToolTipText("Load");
\r
376 int value = chooser.showOpenDialog(this);
\r
378 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
380 File file = chooser.getSelectedFile();
\r
384 InputStreamReader in = new InputStreamReader(new FileInputStream(
\r
387 jalview.binding.JalviewUserColours jucs = new jalview.binding.
\r
388 JalviewUserColours();
\r
389 jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);
\r
392 for (int i = 0; i < jucs.getColourCount(); i++)
\r
394 fr.setColour( jucs.getColour(i).getName(),
\r
395 new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));
\r
401 catch (Exception ex)
\r
403 System.out.println("Error loading User ColourFile\n" + ex);
\r
410 JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(
\r
411 "LAST_DIRECTORY"), new String[] { "fc" },
\r
412 new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");
\r
413 chooser.setFileView(new jalview.io.JalviewFileView());
\r
414 chooser.setDialogTitle("Save Feature Colour Scheme");
\r
415 chooser.setToolTipText("Save");
\r
417 int value = chooser.showSaveDialog(this);
\r
419 if (value == JalviewFileChooser.APPROVE_OPTION)
\r
421 String choice = chooser.getSelectedFile().getPath();
\r
422 jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();
\r
423 ucs.setSchemeName("Sequence Features");
\r
426 PrintWriter out = new PrintWriter(new OutputStreamWriter(
\r
427 new FileOutputStream(choice), "UTF-8"));
\r
429 Enumeration e = fr.featureColours.keys();
\r
430 while(e.hasMoreElements())
\r
434 jalview.binding.Colour col = new jalview.binding.Colour();
\r
435 col.setName(e.nextElement().toString());
\r
436 col.setRGB(jalview.util.Format.getHexString(
\r
437 fr.getColour(col.getName())));
\r
438 ucs.addColour(col);
\r
444 catch (Exception ex)
\r
446 ex.printStackTrace();
\r
451 public void invertSelection()
\r
453 for(int i=0; i<table.getRowCount(); i++)
\r
455 Boolean value = (Boolean)table.getValueAt(i,2);
\r
458 new Boolean(!value.booleanValue()),
\r
464 public void updateFeatureRenderer(Object [][] data)
\r
466 fr.setFeaturePriority( data );
\r
469 if(ap.overviewPanel!=null)
\r
470 ap.overviewPanel.updateOverviewImage();
\r
473 int selectedRow =-1;
\r
476 /////////////////////////////////////////////////////////////////////////
\r
477 // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
\r
478 /////////////////////////////////////////////////////////////////////////
\r
479 class FeatureTableModel
\r
480 extends AbstractTableModel
\r
482 FeatureTableModel(Object[][] data)
\r
487 private String[] columnNames = {"Feature Type", "Colour","Display"};
\r
488 private Object[][] data;
\r
490 public Object[][] getData()
\r
495 public void setData(Object[][] data)
\r
500 public int getColumnCount() {
\r
501 return columnNames.length;
\r
504 public Object[] getRow(int row)
\r
509 public int getRowCount() {
\r
510 return data.length;
\r
513 public String getColumnName(int col) {
\r
514 return columnNames[col];
\r
517 public Object getValueAt(int row, int col) {
\r
518 return data[row][col];
\r
521 public Class getColumnClass(int c) {
\r
522 return getValueAt(0, c).getClass();
\r
525 public boolean isCellEditable(int row, int col) {
\r
526 return col==0 ? false:true;
\r
529 public void setValueAt(Object value, int row, int col) {
\r
530 data[row][col] = value;
\r
531 fireTableCellUpdated(row, col);
\r
532 updateFeatureRenderer(data);
\r
536 class ColorRenderer extends JLabel
\r
537 implements TableCellRenderer {
\r
538 javax.swing.border.Border unselectedBorder = null;
\r
539 javax.swing.border.Border selectedBorder = null;
\r
541 public ColorRenderer() {
\r
542 setOpaque(true); //MUST do this for background to show up.
\r
545 public Component getTableCellRendererComponent(
\r
546 JTable table, Object color,
\r
547 boolean isSelected, boolean hasFocus,
\r
548 int row, int column) {
\r
549 Color newColor = (Color)color;
\r
550 setBackground(newColor);
\r
552 if (selectedBorder == null) {
\r
553 selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
554 table.getSelectionBackground());
\r
556 setBorder(selectedBorder);
\r
558 if (unselectedBorder == null) {
\r
559 unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,
\r
560 table.getBackground());
\r
562 setBorder(unselectedBorder);
\r
565 setToolTipText("RGB value: " + newColor.getRed() + ", "
\r
566 + newColor.getGreen() + ", "
\r
567 + newColor.getBlue());
\r
573 class ColorEditor extends AbstractCellEditor
\r
574 implements TableCellEditor,
\r
576 Color currentColor;
\r
578 JColorChooser colorChooser;
\r
580 protected static final String EDIT = "edit";
\r
582 public ColorEditor() {
\r
583 //Set up the editor (from the table's point of view),
\r
584 //which is a button.
\r
585 //This button brings up the color chooser dialog,
\r
586 //which is the editor from the user's point of view.
\r
587 button = new JButton();
\r
588 button.setActionCommand(EDIT);
\r
589 button.addActionListener(this);
\r
590 button.setBorderPainted(false);
\r
591 //Set up the dialog that the button brings up.
\r
592 colorChooser = new JColorChooser();
\r
593 dialog = JColorChooser.createDialog(button,
\r
594 "Select new Colour",
\r
597 this, //OK button handler
\r
598 null); //no CANCEL button handler
\r
602 * Handles events from the editor button and from
\r
603 * the dialog's OK button.
\r
605 public void actionPerformed(ActionEvent e) {
\r
607 if (EDIT.equals(e.getActionCommand())) {
\r
608 //The user has clicked the cell, so
\r
609 //bring up the dialog.
\r
610 button.setBackground(currentColor);
\r
611 colorChooser.setColor(currentColor);
\r
612 dialog.setVisible(true);
\r
614 //Make the renderer reappear.
\r
615 fireEditingStopped();
\r
617 } else { //User pressed dialog's "OK" button.
\r
618 currentColor = colorChooser.getColor();
\r
622 //Implement the one CellEditor method that AbstractCellEditor doesn't.
\r
623 public Object getCellEditorValue() {
\r
624 return currentColor;
\r
627 //Implement the one method defined by TableCellEditor.
\r
628 public Component getTableCellEditorComponent(JTable table,
\r
630 boolean isSelected,
\r
633 currentColor = (Color)value;
\r