f7cc65edf84d1aa93ec5ff40ca9703b0ace5cd0d
[jalview.git] / src / jalview / gui / FeatureRenderer.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
3  * Copyright (C) 2014 The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import jalview.datamodel.SearchResults;
24 import jalview.datamodel.SequenceFeature;
25 import jalview.datamodel.SequenceI;
26 import jalview.schemes.GraduatedColor;
27 import jalview.util.MessageManager;
28
29 import java.awt.BorderLayout;
30 import java.awt.Color;
31 import java.awt.Dimension;
32 import java.awt.Font;
33 import java.awt.GridLayout;
34 import java.awt.event.ActionEvent;
35 import java.awt.event.ActionListener;
36 import java.awt.event.ItemEvent;
37 import java.awt.event.ItemListener;
38 import java.awt.event.MouseAdapter;
39 import java.awt.event.MouseEvent;
40
41 import javax.swing.JColorChooser;
42 import javax.swing.JComboBox;
43 import javax.swing.JLabel;
44 import javax.swing.JOptionPane;
45 import javax.swing.JPanel;
46 import javax.swing.JScrollPane;
47 import javax.swing.JSpinner;
48 import javax.swing.JTextArea;
49 import javax.swing.JTextField;
50 import javax.swing.SwingConstants;
51
52 /**
53  * DOCUMENT ME!
54  * 
55  * @author $author$
56  * @version $Revision$
57  */
58 public class FeatureRenderer extends jalview.renderer.seqfeatures.FeatureRenderer implements jalview.api.FeatureRenderer
59 {
60   Color resBoxColour;
61
62   AlignmentPanel ap;
63
64   /**
65    * Creates a new FeatureRenderer object.
66    * 
67    * @param av
68    *          DOCUMENT ME!
69    */
70   public FeatureRenderer(AlignmentPanel ap)
71   {
72     super();
73     this.ap = ap;
74     this.av = ap.av;
75     if (ap != null && ap.getSeqPanel() != null && ap.getSeqPanel().seqCanvas != null
76             && ap.getSeqPanel().seqCanvas.fr != null)
77     {
78       transferSettings(ap.getSeqPanel().seqCanvas.fr);
79     }
80   }
81
82   // // /////////////
83   // // Feature Editing Dialog
84   // // Will be refactored in next release.
85
86   static String lastFeatureAdded;
87
88   static String lastFeatureGroupAdded;
89
90   static String lastDescriptionAdded;
91
92   Object oldcol, fcol;
93
94   int featureIndex = 0;
95
96   boolean amendFeatures(final SequenceI[] sequences,
97           final SequenceFeature[] features, boolean newFeatures,
98           final AlignmentPanel ap)
99   {
100
101     featureIndex = 0;
102
103     final JPanel bigPanel = new JPanel(new BorderLayout());
104     final JComboBox overlaps;
105     final JTextField name = new JTextField(25);
106     final JTextField source = new JTextField(25);
107     final JTextArea description = new JTextArea(3, 25);
108     final JSpinner start = new JSpinner();
109     final JSpinner end = new JSpinner();
110     start.setPreferredSize(new Dimension(80, 20));
111     end.setPreferredSize(new Dimension(80, 20));
112     final FeatureRenderer me = this;
113     final JLabel colour = new JLabel();
114     colour.setOpaque(true);
115     // colour.setBorder(BorderFactory.createEtchedBorder());
116     colour.setMaximumSize(new Dimension(30, 16));
117     colour.addMouseListener(new MouseAdapter()
118     {
119       FeatureColourChooser fcc = null;
120
121       public void mousePressed(MouseEvent evt)
122       {
123         if (fcol instanceof Color)
124         {
125           Color col = JColorChooser.showDialog(Desktop.desktop,
126                   MessageManager.getString("label.select_feature_colour"), ((Color) fcol));
127           if (col != null)
128           {
129             fcol = col;
130             updateColourButton(bigPanel, colour, col);
131           }
132         }
133         else
134         {
135
136           if (fcc == null)
137           {
138             final String type = features[featureIndex].getType();
139             fcc = new FeatureColourChooser(me, type);
140             fcc.setRequestFocusEnabled(true);
141             fcc.requestFocus();
142
143             fcc.addActionListener(new ActionListener()
144             {
145
146               public void actionPerformed(ActionEvent e)
147               {
148                 fcol = fcc.getLastColour();
149                 fcc = null;
150                 setColour(type, fcol);
151                 updateColourButton(bigPanel, colour, fcol);
152               }
153             });
154
155           }
156         }
157       }
158     });
159     JPanel tmp = new JPanel();
160     JPanel panel = new JPanel(new GridLayout(3, 1));
161
162     // /////////////////////////////////////
163     // /MULTIPLE FEATURES AT SELECTED RESIDUE
164     if (!newFeatures && features.length > 1)
165     {
166       panel = new JPanel(new GridLayout(4, 1));
167       tmp = new JPanel();
168       tmp.add(new JLabel(MessageManager.getString("label.select_feature")));
169       overlaps = new JComboBox();
170       for (int i = 0; i < features.length; i++)
171       {
172         overlaps.addItem(features[i].getType() + "/"
173                 + features[i].getBegin() + "-" + features[i].getEnd()
174                 + " (" + features[i].getFeatureGroup() + ")");
175       }
176
177       tmp.add(overlaps);
178
179       overlaps.addItemListener(new ItemListener()
180       {
181         public void itemStateChanged(ItemEvent e)
182         {
183           int index = overlaps.getSelectedIndex();
184           if (index != -1)
185           {
186             featureIndex = index;
187             name.setText(features[index].getType());
188             description.setText(features[index].getDescription());
189             source.setText(features[index].getFeatureGroup());
190             start.setValue(new Integer(features[index].getBegin()));
191             end.setValue(new Integer(features[index].getEnd()));
192
193             SearchResults highlight = new SearchResults();
194             highlight.addResult(sequences[0], features[index].getBegin(),
195                     features[index].getEnd());
196
197             ap.getSeqPanel().seqCanvas.highlightSearchResults(highlight);
198
199           }
200           Object col = getFeatureStyle(name.getText());
201           if (col == null)
202           {
203             col = new jalview.schemes.UserColourScheme()
204                     .createColourFromName(name.getText());
205           }
206           oldcol = fcol = col;
207           updateColourButton(bigPanel, colour, col);
208         }
209       });
210
211       panel.add(tmp);
212     }
213     // ////////
214     // ////////////////////////////////////
215
216     tmp = new JPanel();
217     panel.add(tmp);
218     tmp.add(new JLabel(MessageManager.getString("label.name"), JLabel.RIGHT));
219     tmp.add(name);
220
221     tmp = new JPanel();
222     panel.add(tmp);
223     tmp.add(new JLabel(MessageManager.getString("label.group") + ":",
224             JLabel.RIGHT));
225     tmp.add(source);
226
227     tmp = new JPanel();
228     panel.add(tmp);
229     tmp.add(new JLabel(MessageManager.getString("label.colour"),
230             JLabel.RIGHT));
231     tmp.add(colour);
232     colour.setPreferredSize(new Dimension(150, 15));
233     colour.setFont(new java.awt.Font("Verdana", Font.PLAIN, 9));
234     colour.setForeground(Color.black);
235     colour.setHorizontalAlignment(SwingConstants.CENTER);
236     colour.setVerticalAlignment(SwingConstants.CENTER);
237     colour.setHorizontalTextPosition(SwingConstants.CENTER);
238     colour.setVerticalTextPosition(SwingConstants.CENTER);
239     bigPanel.add(panel, BorderLayout.NORTH);
240
241     panel = new JPanel();
242     panel.add(new JLabel(MessageManager.getString("label.description"),
243             JLabel.RIGHT));
244     description.setFont(JvSwingUtils.getTextAreaFont());
245     description.setLineWrap(true);
246     panel.add(new JScrollPane(description));
247
248     if (!newFeatures)
249     {
250       bigPanel.add(panel, BorderLayout.SOUTH);
251
252       panel = new JPanel();
253       panel.add(new JLabel(MessageManager.getString("label.start"),
254               JLabel.RIGHT));
255       panel.add(start);
256       panel.add(new JLabel(MessageManager.getString("label.end"),
257               JLabel.RIGHT));
258       panel.add(end);
259       bigPanel.add(panel, BorderLayout.CENTER);
260     }
261     else
262     {
263       bigPanel.add(panel, BorderLayout.CENTER);
264     }
265
266     if (lastFeatureAdded == null)
267     {
268       if (features[0].type != null)
269       {
270         lastFeatureAdded = features[0].type;
271       }
272       else
273       {
274         lastFeatureAdded = "feature_1";
275       }
276     }
277
278     if (lastFeatureGroupAdded == null)
279     {
280       if (features[0].featureGroup != null)
281       {
282         lastFeatureGroupAdded = features[0].featureGroup;
283       }
284       else
285       {
286         lastFeatureGroupAdded = "Jalview";
287       }
288     }
289
290     if (newFeatures)
291     {
292       name.setText(lastFeatureAdded);
293       source.setText(lastFeatureGroupAdded);
294     }
295     else
296     {
297       name.setText(features[0].getType());
298       source.setText(features[0].getFeatureGroup());
299     }
300
301     start.setValue(new Integer(features[0].getBegin()));
302     end.setValue(new Integer(features[0].getEnd()));
303     description.setText(features[0].getDescription());
304     updateColourButton(bigPanel, colour,
305             (oldcol = fcol = getFeatureStyle(name.getText())));
306     Object[] options;
307     if (!newFeatures)
308     {
309       options = new Object[]
310       { "Amend", "Delete", "Cancel" };
311     }
312     else
313     {
314       options = new Object[]
315       { "OK", "Cancel" };
316     }
317
318     String title = newFeatures ? MessageManager.getString("label.create_new_sequence_features")
319             : MessageManager.formatMessage("label.amend_delete_features", new String[]{sequences[0].getName()});
320
321     int reply = JOptionPane.showInternalOptionDialog(Desktop.desktop,
322             bigPanel, title, JOptionPane.YES_NO_CANCEL_OPTION,
323             JOptionPane.QUESTION_MESSAGE, null, options, MessageManager.getString("action.ok"));
324
325     jalview.io.FeaturesFile ffile = new jalview.io.FeaturesFile();
326
327     if (reply == JOptionPane.OK_OPTION && name.getText().length() > 0)
328     {
329       // This ensures that the last sequence
330       // is refreshed and new features are rendered
331       lastSeq = null;
332       lastFeatureAdded = name.getText().trim();
333       lastFeatureGroupAdded = source.getText().trim();
334       lastDescriptionAdded = description.getText().replaceAll("\n", " ");
335       // TODO: determine if the null feature group is valid
336       if (lastFeatureGroupAdded.length() < 1)
337       {
338         lastFeatureGroupAdded = null;
339       }
340     }
341
342     if (!newFeatures)
343     {
344       SequenceFeature sf = features[featureIndex];
345
346       if (reply == JOptionPane.NO_OPTION)
347       {
348         sequences[0].getDatasetSequence().deleteFeature(sf);
349       }
350       else if (reply == JOptionPane.YES_OPTION)
351       {
352         sf.type = lastFeatureAdded;
353         sf.featureGroup = lastFeatureGroupAdded;
354         sf.description = lastDescriptionAdded;
355
356         setColour(sf.type, fcol);
357         getFeaturesDisplayed().setVisible(sf.type);
358
359         try
360         {
361           sf.begin = ((Integer) start.getValue()).intValue();
362           sf.end = ((Integer) end.getValue()).intValue();
363         } catch (NumberFormatException ex)
364         {
365         }
366
367         ffile.parseDescriptionHTML(sf, false);
368       }
369     }
370     else
371     // NEW FEATURES ADDED
372     {
373       if (reply == JOptionPane.OK_OPTION && lastFeatureAdded.length() > 0)
374       {
375         for (int i = 0; i < sequences.length; i++)
376         {
377           features[i].type = lastFeatureAdded;
378           // fix for JAL-1538 - always set feature group here
379           features[i].featureGroup = lastFeatureGroupAdded;
380           features[i].description = lastDescriptionAdded;
381           sequences[i].addSequenceFeature(features[i]);
382           ffile.parseDescriptionHTML(features[i], false);
383         }
384
385         if (lastFeatureGroupAdded != null)
386         {
387           setGroupVisibility(lastFeatureGroupAdded, true);
388         }
389         setColour(lastFeatureAdded, fcol);
390         setVisible(lastFeatureAdded);
391
392         findAllFeatures(false);
393
394         ap.paintAlignment(true);
395
396         return true;
397       }
398       else
399       {
400         return false;
401       }
402     }
403
404     ap.paintAlignment(true);
405
406     return true;
407   }
408
409
410   /**
411    * update the amend feature button dependent on the given style
412    * 
413    * @param bigPanel
414    * @param col
415    * @param col2
416    */
417   protected void updateColourButton(JPanel bigPanel, JLabel colour,
418           Object col2)
419   {
420     colour.removeAll();
421     colour.setIcon(null);
422     colour.setToolTipText(null);
423     colour.setText("");
424
425     if (col2 instanceof Color)
426     {
427       colour.setBackground((Color) col2);
428     }
429     else
430     {
431       colour.setBackground(bigPanel.getBackground());
432       colour.setForeground(Color.black);
433       FeatureSettings.renderGraduatedColor(colour, (GraduatedColor) col2);
434       // colour.setForeground(colour.getBackground());
435     }
436   }
437 }