License added to new files
[jalview.git] / src / jalview / gui / FeatureSettings.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\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
9  *\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
14  *\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
18  */\r
19 package jalview.gui;\r
20 \r
21 import jalview.datamodel.*;\r
22 import javax.swing.*;\r
23 import javax.swing.event.*;\r
24 import java.awt.*;\r
25 import java.util.*;\r
26 import javax.swing.BorderFactory;\r
27 import java.awt.event.*;\r
28 import javax.swing.table.*;\r
29 import java.io.*;\r
30 import jalview.io.JalviewFileChooser;\r
31 \r
32 public class FeatureSettings extends JPanel\r
33 {\r
34 \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
41   JTable table;\r
42 \r
43   public FeatureSettings(AlignViewport av, final AlignmentPanel ap)\r
44   {\r
45     this.ap = ap;\r
46     this.av = av;\r
47     fr = ap.seqPanel.seqCanvas.getFeatureRenderer();\r
48     av.alignment.getSequences();\r
49     frame = new JInternalFrame();\r
50     frame.setContentPane(this);\r
51     Desktop.addInternalFrame(frame, "Sequence Feature Settings", 400, 300);\r
52 \r
53     setTableData();\r
54 \r
55     final JSlider transparency = new JSlider(0, 70, 0);\r
56     transparency.addChangeListener(new ChangeListener()\r
57     {\r
58       public void stateChanged(ChangeEvent evt)\r
59       {\r
60         fr.setTransparency( (float) (100 - transparency.getValue()) / 100f);\r
61         ap.repaint();\r
62       }\r
63     });\r
64 \r
65     JPanel transPanel = new JPanel(new FlowLayout());\r
66     transPanel.add(new JLabel("Transparency"));\r
67     transPanel.add(transparency);\r
68 \r
69     //////////////////////////////////////////////\r
70     //We're going to need those OK cancel buttons\r
71     JPanel buttonPanel = new JPanel(new FlowLayout());\r
72     JButton button = new JButton("OK");\r
73     button.addActionListener(new ActionListener()\r
74     {\r
75       public void actionPerformed(ActionEvent evt)\r
76       {\r
77         try\r
78         {\r
79           frame.setClosed(true);\r
80         }\r
81         catch (Exception exe)\r
82         {}\r
83       }\r
84     });\r
85     buttonPanel.add(button);\r
86     button = new JButton("Cancel");\r
87     button.addActionListener(new ActionListener()\r
88     {\r
89       public void actionPerformed(ActionEvent evt)\r
90       {\r
91         try\r
92         {\r
93           updateFeatureRenderer(originalData);\r
94           frame.setClosed(true);\r
95         }\r
96         catch (Exception exe)\r
97         {}\r
98       }\r
99     });\r
100     buttonPanel.add(button);\r
101 \r
102     button = new JButton("Load Colours");\r
103     button.addActionListener(new ActionListener()\r
104     {\r
105       public void actionPerformed(ActionEvent evt)\r
106       {\r
107         load();\r
108       }\r
109     });\r
110     buttonPanel.add(button);\r
111     button = new JButton("Save Colours");\r
112     button.addActionListener(new ActionListener()\r
113     {\r
114       public void actionPerformed(ActionEvent evt)\r
115       {\r
116         save();\r
117       }\r
118     });\r
119     buttonPanel.add(button);\r
120 \r
121     this.setLayout(new BorderLayout());\r
122     JPanel bigPanel = new JPanel(new BorderLayout());\r
123     bigPanel.add(transPanel, BorderLayout.SOUTH);\r
124     bigPanel.add(scrollPane, BorderLayout.CENTER);\r
125 \r
126     add(bigPanel, BorderLayout.CENTER);\r
127     add(buttonPanel, BorderLayout.SOUTH);\r
128 \r
129 \r
130   }\r
131 \r
132   void setTableData()\r
133   {\r
134     Vector allFeatures = new Vector();\r
135     Vector features;\r
136     Enumeration e;\r
137     SequenceFeature sf;\r
138 \r
139     for(int i=0; i< av.alignment.getHeight(); i++)\r
140     {\r
141        features = av.alignment.getSequenceAt(i).getDatasetSequence().getSequenceFeatures();\r
142        if(features==null)\r
143          continue;\r
144 \r
145        e = features.elements();\r
146        while(e.hasMoreElements())\r
147        {\r
148          sf = (SequenceFeature)e.nextElement();\r
149          if(!allFeatures.contains(sf.getType()))\r
150          {\r
151            allFeatures.addElement(sf.getType());\r
152          }\r
153        }\r
154     }\r
155     if(allFeatures.size()<1)\r
156      {\r
157        try{\r
158          frame.setClosed(true);\r
159        }catch(Exception ex){}\r
160        return;\r
161      }\r
162 \r
163     int fSize = allFeatures.size();\r
164 \r
165     String type;\r
166     boolean originalExists = false;\r
167     if(originalData!=null)\r
168       originalExists = true;\r
169     else\r
170       originalData = new Object[fSize][3];\r
171 \r
172     Object [][] data = new Object[fSize][3];\r
173     for(int i=0; i<fSize; i++)\r
174     {\r
175       type = allFeatures.elementAt(i).toString();\r
176       Color col = fr.getColour(type);\r
177       data[i][0]=type;\r
178       data[i][1]=col;\r
179       if(fr.featuresDisplayed!=null)\r
180          data[i][2] = new Boolean(fr.featuresDisplayed.contains(type));\r
181       else\r
182         data[i][2] = new Boolean(true);\r
183 \r
184       if(!originalExists)\r
185       {\r
186         originalData[i][0] = type;\r
187         originalData[i][1] = col;\r
188         if (fr.featuresDisplayed != null)\r
189           originalData[i][2] = new Boolean(fr.featuresDisplayed.contains(type));\r
190         else\r
191           originalData[i][2] = new Boolean(true);\r
192       }\r
193     }\r
194     ////////////////////////////////////\r
195         //Now build the table\r
196         table = new JTable(new FeatureTableModel(data));\r
197         scrollPane.setViewportView(table);\r
198         table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));\r
199         table.setFont(new Font("Verdana", Font.PLAIN, 12));\r
200         table.setDefaultRenderer(Color.class,\r
201                              new ColorRenderer());\r
202 \r
203         table.setDefaultEditor(Color.class,\r
204                           new ColorEditor());\r
205 \r
206         table.getColumnModel().getColumn(0).setPreferredWidth(200);\r
207 \r
208         table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);\r
209 \r
210         table.addMouseListener(new MouseAdapter()\r
211             {\r
212               public void mousePressed(MouseEvent evt)\r
213               {\r
214                 selectedRow = table.rowAtPoint(evt.getPoint());\r
215               }\r
216             });\r
217 \r
218         table.addMouseMotionListener(new MouseMotionAdapter()\r
219             {\r
220               public void mouseDragged(MouseEvent evt)\r
221               {\r
222                 int newRow = table.rowAtPoint(evt.getPoint());\r
223                 if(newRow!=selectedRow\r
224                    && selectedRow!=-1\r
225                    && newRow!=-1)\r
226                 {\r
227                   Object[] temp = new Object[3];\r
228                   temp[0] = table.getValueAt(selectedRow, 0);\r
229                   temp[1] = table.getValueAt(selectedRow, 1);\r
230                   temp[2] = table.getValueAt(selectedRow, 2);\r
231 \r
232                   table.setValueAt(table.getValueAt(newRow, 0), selectedRow, 0);\r
233                   table.setValueAt(table.getValueAt(newRow, 1), selectedRow, 1);\r
234                   table.setValueAt(table.getValueAt(newRow, 2), selectedRow, 2);\r
235 \r
236                   table.setValueAt(temp[0], newRow, 0);\r
237                   table.setValueAt(temp[1], newRow, 1);\r
238                   table.setValueAt(temp[2], newRow, 2);\r
239 \r
240                   selectedRow = newRow;\r
241                 }\r
242               }\r
243         });\r
244 \r
245   }\r
246 \r
247   void load()\r
248   {\r
249     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(\r
250                  "LAST_DIRECTORY"), new String[] { "fc" },\r
251              new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");\r
252      chooser.setFileView(new jalview.io.JalviewFileView());\r
253      chooser.setDialogTitle("Load Feature Colours");\r
254      chooser.setToolTipText("Load");\r
255 \r
256      int value = chooser.showOpenDialog(this);\r
257 \r
258      if (value == JalviewFileChooser.APPROVE_OPTION)\r
259      {\r
260        File file = chooser.getSelectedFile();\r
261 \r
262        try\r
263        {\r
264          InputStreamReader in = new InputStreamReader(new FileInputStream(\r
265              file), "UTF-8");\r
266 \r
267          jalview.binding.JalviewUserColours jucs = new jalview.binding.\r
268              JalviewUserColours();\r
269          jucs = (jalview.binding.JalviewUserColours) jucs.unmarshal(in);\r
270 \r
271 \r
272          for (int i = 0; i < jucs.getColourCount(); i++)\r
273          {\r
274            fr.setColour( jucs.getColour(i).getName(),\r
275                           new Color(Integer.parseInt( jucs.getColour(i).getRGB(), 16)));\r
276          }\r
277 \r
278          setTableData();\r
279          ap.repaint();\r
280        }\r
281        catch (Exception ex)\r
282        {\r
283          System.out.println("Error loading User ColourFile\n" + ex);\r
284        }\r
285      }\r
286   }\r
287 \r
288   void save()\r
289   {\r
290     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache.getProperty(\r
291                 "LAST_DIRECTORY"), new String[] { "fc" },\r
292             new String[] { "Sequence Feature Colours" }, "Sequence Feature Colours");\r
293     chooser.setFileView(new jalview.io.JalviewFileView());\r
294     chooser.setDialogTitle("Save Feature Colour Scheme");\r
295     chooser.setToolTipText("Save");\r
296 \r
297     int value = chooser.showSaveDialog(this);\r
298 \r
299     if (value == JalviewFileChooser.APPROVE_OPTION)\r
300     {\r
301         String choice = chooser.getSelectedFile().getPath();\r
302         jalview.binding.JalviewUserColours ucs = new jalview.binding.JalviewUserColours();\r
303         ucs.setSchemeName("Sequence Features");\r
304         try\r
305         {\r
306             PrintWriter out = new PrintWriter(new OutputStreamWriter(\r
307                         new FileOutputStream(choice), "UTF-8"));\r
308 \r
309             Enumeration e = fr.featureColours.keys();\r
310            while(e.hasMoreElements())\r
311            {\r
312 \r
313 \r
314                 jalview.binding.Colour col = new jalview.binding.Colour();\r
315                 col.setName(e.nextElement().toString());\r
316                 col.setRGB(jalview.util.Format.getHexString(\r
317                         fr.getColour(col.getName())));\r
318                 ucs.addColour(col);\r
319             }\r
320 \r
321             ucs.marshal(out);\r
322             out.close();\r
323         }\r
324         catch (Exception ex)\r
325         {\r
326             ex.printStackTrace();\r
327         }\r
328     }\r
329 \r
330   }\r
331 \r
332   public void updateFeatureRenderer(Object [][] data)\r
333   {\r
334     fr.setFeaturePriority( data );\r
335     ap.repaint();\r
336   }\r
337 \r
338   int selectedRow =-1;\r
339 \r
340 \r
341   /////////////////////////////////////////////////////////////////////////\r
342   // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html\r
343   /////////////////////////////////////////////////////////////////////////\r
344   class FeatureTableModel\r
345       extends AbstractTableModel\r
346   {\r
347     FeatureTableModel(Object[][] data)\r
348     {\r
349       this.data = data;\r
350     }\r
351 \r
352     private String[] columnNames = {"Feature Type", "Colour","Display"};\r
353           private Object[][] data;\r
354 \r
355           public Object[][] getData()\r
356           {\r
357             return data;\r
358           }\r
359 \r
360           public int getColumnCount() {\r
361               return columnNames.length;\r
362           }\r
363 \r
364           public Object[] getRow(int row)\r
365           {\r
366             return data[row];\r
367           }\r
368 \r
369           public int getRowCount() {\r
370               return data.length;\r
371           }\r
372 \r
373           public String getColumnName(int col) {\r
374               return columnNames[col];\r
375           }\r
376 \r
377           public Object getValueAt(int row, int col) {\r
378               return data[row][col];\r
379           }\r
380 \r
381           public Class getColumnClass(int c) {\r
382               return getValueAt(0, c).getClass();\r
383           }\r
384 \r
385           public boolean isCellEditable(int row, int col) {\r
386               return col==0 ? false:true;\r
387           }\r
388 \r
389           public void setValueAt(Object value, int row, int col) {\r
390               data[row][col] = value;\r
391               fireTableCellUpdated(row, col);\r
392               updateFeatureRenderer(data);\r
393           }\r
394 \r
395     }\r
396     class ColorRenderer extends JLabel\r
397                               implements TableCellRenderer {\r
398        javax.swing.border.Border unselectedBorder = null;\r
399        javax.swing.border.Border selectedBorder = null;\r
400 \r
401        public ColorRenderer() {\r
402            setOpaque(true); //MUST do this for background to show up.\r
403        }\r
404 \r
405        public Component getTableCellRendererComponent(\r
406                                JTable table, Object color,\r
407                                boolean isSelected, boolean hasFocus,\r
408                                int row, int column) {\r
409            Color newColor = (Color)color;\r
410            setBackground(newColor);\r
411                if (isSelected) {\r
412                    if (selectedBorder == null) {\r
413                        selectedBorder = BorderFactory.createMatteBorder(2,5,2,5,\r
414                                                  table.getSelectionBackground());\r
415                    }\r
416                    setBorder(selectedBorder);\r
417                } else {\r
418                    if (unselectedBorder == null) {\r
419                        unselectedBorder = BorderFactory.createMatteBorder(2,5,2,5,\r
420                                                  table.getBackground());\r
421                    }\r
422                    setBorder(unselectedBorder);\r
423                }\r
424 \r
425            setToolTipText("RGB value: " + newColor.getRed() + ", "\r
426                                         + newColor.getGreen() + ", "\r
427                                         + newColor.getBlue());\r
428            return this;\r
429        }\r
430    }\r
431 }\r
432 \r
433  class ColorEditor extends AbstractCellEditor\r
434                           implements TableCellEditor,\r
435                                      ActionListener {\r
436      Color currentColor;\r
437      JButton button;\r
438      JColorChooser colorChooser;\r
439      JDialog dialog;\r
440      protected static final String EDIT = "edit";\r
441 \r
442      public ColorEditor() {\r
443          //Set up the editor (from the table's point of view),\r
444          //which is a button.\r
445          //This button brings up the color chooser dialog,\r
446          //which is the editor from the user's point of view.\r
447          button = new JButton();\r
448          button.setActionCommand(EDIT);\r
449          button.addActionListener(this);\r
450          button.setBorderPainted(false);\r
451          //Set up the dialog that the button brings up.\r
452          colorChooser = new JColorChooser();\r
453          dialog = JColorChooser.createDialog(button,\r
454                                          "Select new Colour",\r
455                                          true,  //modal\r
456                                          colorChooser,\r
457                                          this,  //OK button handler\r
458                                          null); //no CANCEL button handler\r
459      }\r
460 \r
461      /**\r
462       * Handles events from the editor button and from\r
463       * the dialog's OK button.\r
464       */\r
465      public void actionPerformed(ActionEvent e) {\r
466 \r
467           if (EDIT.equals(e.getActionCommand())) {\r
468              //The user has clicked the cell, so\r
469              //bring up the dialog.\r
470              button.setBackground(currentColor);\r
471              colorChooser.setColor(currentColor);\r
472              dialog.setVisible(true);\r
473 \r
474              //Make the renderer reappear.\r
475              fireEditingStopped();\r
476 \r
477          } else { //User pressed dialog's "OK" button.\r
478              currentColor = colorChooser.getColor();\r
479          }\r
480      }\r
481 \r
482      //Implement the one CellEditor method that AbstractCellEditor doesn't.\r
483      public Object getCellEditorValue() {\r
484          return currentColor;\r
485      }\r
486 \r
487      //Implement the one method defined by TableCellEditor.\r
488      public Component getTableCellEditorComponent(JTable table,\r
489                                                   Object value,\r
490                                                   boolean isSelected,\r
491                                                   int row,\r
492                                                   int column) {\r
493          currentColor = (Color)value;\r
494          return button;\r
495      }\r
496 }\r