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