568ca475f98847f4c99c90abd6fe320dc36d6053
[jalview.git] / src / jalview / gui / AnnotationExporter.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ 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 java.util.Locale;
24
25 import jalview.api.FeatureRenderer;
26 import jalview.bin.Cache;
27 import jalview.datamodel.AlignmentAnnotation;
28 import jalview.datamodel.SequenceI;
29 import jalview.io.AnnotationFile;
30 import jalview.io.FeaturesFile;
31 import jalview.io.JalviewFileChooser;
32 import jalview.io.JalviewFileView;
33 import jalview.util.MessageManager;
34
35 import java.awt.Color;
36 import java.awt.Dimension;
37 import java.awt.event.ActionEvent;
38 import java.awt.event.ActionListener;
39 import java.io.FileWriter;
40 import java.io.PrintWriter;
41
42 import javax.swing.BoxLayout;
43 import javax.swing.ButtonGroup;
44 import javax.swing.JButton;
45 import javax.swing.JCheckBox;
46 import javax.swing.JInternalFrame;
47 import javax.swing.JLabel;
48 import javax.swing.JLayeredPane;
49 import javax.swing.JPanel;
50 import javax.swing.JRadioButton;
51 import javax.swing.SwingConstants;
52
53 /**
54  * 
55  * GUI dialog for exporting features or alignment annotations depending upon
56  * which method is called.
57  * 
58  * @author AMW
59  * 
60  */
61 public class AnnotationExporter extends JPanel
62 {
63   private JInternalFrame frame;
64
65   private AlignmentPanel ap;
66
67   /*
68    * true if exporting features, false if exporting annotations
69    */
70   private boolean exportFeatures = true;
71
72   private AlignmentAnnotation[] annotations;
73
74   private boolean wholeView;
75
76   /*
77    * option to export linked (CDS/peptide) features when shown 
78    * on the alignment, converted to this alignment's coordinates
79    */
80   private JCheckBox includeLinkedFeatures;
81
82   /*
83    * output format option shown for feature export
84    */
85   JRadioButton GFFFormat = new JRadioButton();
86
87   /*
88    * output format option shown for annotation export
89    */
90   JRadioButton CSVFormat = new JRadioButton();
91
92   private JPanel linkedFeaturesPanel;
93
94   /**
95    * Constructor
96    * 
97    * @param panel
98    */
99   public AnnotationExporter(AlignmentPanel panel)
100   {
101     this.ap = panel;
102     try
103     {
104       jbInit();
105     } catch (Exception ex)
106     {
107       ex.printStackTrace();
108     }
109
110     frame = new JInternalFrame();
111     frame.setContentPane(this);
112     frame.setLayer(JLayeredPane.PALETTE_LAYER);
113     Dimension preferredSize = frame.getPreferredSize();
114     Desktop.addInternalFrame(frame, "", true, preferredSize.width,
115             preferredSize.height, true, true);
116   }
117
118   /**
119    * Configures the dialog for options to export visible features. If from a split
120    * frame panel showing linked features, make the option to include these in the
121    * export visible.
122    */
123   public void exportFeatures()
124   {
125     exportFeatures = true;
126     CSVFormat.setVisible(false);
127     if (ap.av.isShowComplementFeatures())
128     {
129       linkedFeaturesPanel.setVisible(true);
130       frame.pack();
131     }
132     frame.setTitle(MessageManager.getString("label.export_features"));
133   }
134
135   /**
136    * Configures the dialog for options to export all visible annotations
137    */
138   public void exportAnnotations()
139   {
140     boolean showAnnotation = ap.av.isShowAnnotation();
141     exportAnnotation(showAnnotation ? null
142             : ap.av.getAlignment().getAlignmentAnnotation(), true);
143   }
144
145   /**
146    * Configures the dialog for options to export the given annotation row
147    * 
148    * @param toExport
149    */
150   public void exportAnnotation(AlignmentAnnotation toExport)
151   {
152     exportAnnotation(new AlignmentAnnotation[] { toExport }, false);
153   }
154
155   private void exportAnnotation(AlignmentAnnotation[] toExport,
156           boolean forWholeView)
157   {
158     wholeView = forWholeView;
159     annotations = toExport;
160     exportFeatures = false;
161     GFFFormat.setVisible(false);
162     CSVFormat.setVisible(true);
163     frame.setTitle(MessageManager.getString("label.export_annotations"));
164   }
165
166   private void toFile_actionPerformed()
167   {
168     // TODO: JAL-3048 JalviewFileChooser - Save option
169     JalviewFileChooser chooser = new JalviewFileChooser(
170             Cache.getProperty("LAST_DIRECTORY"));
171
172     chooser.setFileView(new JalviewFileView());
173     chooser.setDialogTitle(exportFeatures
174             ? MessageManager.getString("label.save_features_to_file")
175             : MessageManager.getString("label.save_annotation_to_file"));
176     chooser.setToolTipText(MessageManager.getString("action.save"));
177
178     int value = chooser.showSaveDialog(this);
179
180     if (value == JalviewFileChooser.APPROVE_OPTION)
181     {
182       String text = getText();
183
184       try
185       {
186         PrintWriter out = new PrintWriter(
187                 new FileWriter(chooser.getSelectedFile()));
188         out.print(text);
189         out.close();
190       } catch (Exception ex)
191       {
192         ex.printStackTrace();
193       }
194     }
195
196     close_actionPerformed();
197   }
198
199   /**
200    * Answers the text to output for either Features (in GFF or Jalview format) or
201    * Annotations (in CSV or Jalview format)
202    * 
203    * @return
204    */
205   private String getText()
206   {
207     return exportFeatures ? getFeaturesText() : getAnnotationsText();
208   }
209
210   /**
211    * Returns the text contents for output of annotations in either CSV or Jalview
212    * format
213    * 
214    * @return
215    */
216   private String getAnnotationsText()
217   {
218     String text;
219     if (CSVFormat.isSelected())
220     {
221       text = new AnnotationFile().printCSVAnnotations(annotations);
222     }
223     else
224     {
225       if (wholeView)
226       {
227         text = new AnnotationFile().printAnnotationsForView(ap.av);
228       }
229       else
230       {
231         text = new AnnotationFile().printAnnotations(annotations, null,
232                 null);
233       }
234     }
235     return text;
236   }
237
238   /**
239    * Returns the text contents for output of features in either GFF or Jalview
240    * format
241    * 
242    * @return
243    */
244   private String getFeaturesText()
245   {
246     String text;
247     SequenceI[] sequences = ap.av.getAlignment().getSequencesArray();
248     boolean includeNonPositional = ap.av.isShowNPFeats();
249
250     FeaturesFile formatter = new FeaturesFile();
251     final FeatureRenderer fr = ap.getFeatureRenderer();
252     boolean includeComplement = includeLinkedFeatures.isSelected();
253
254     if (GFFFormat.isSelected())
255     {
256       text = formatter.printGffFormat(sequences, fr, includeNonPositional,
257               includeComplement);
258     }
259     else
260     {
261       text = formatter.printJalviewFormat(sequences, fr,
262               includeNonPositional, includeComplement);
263     }
264     return text;
265   }
266
267   private void toTextbox_actionPerformed()
268   {
269     CutAndPasteTransfer cap = new CutAndPasteTransfer();
270
271     try
272     {
273       String text = getText();
274       cap.setText(text);
275       Desktop.addInternalFrame(cap, (exportFeatures ? MessageManager
276               .formatMessage("label.features_for_params", new String[]
277               { ap.alignFrame.getTitle() })
278               : MessageManager.formatMessage("label.annotations_for_params",
279                       new String[]
280                       { ap.alignFrame.getTitle() })),
281               600, 500);
282     } catch (OutOfMemoryError oom)
283     {
284       new OOMWarning((exportFeatures ? MessageManager.formatMessage(
285               "label.generating_features_for_params", new String[]
286               { ap.alignFrame.getTitle() })
287               : MessageManager.formatMessage(
288                       "label.generating_annotations_for_params",
289                       new String[]
290                       { ap.alignFrame.getTitle() })),
291               oom);
292       cap.dispose();
293     }
294
295     close_actionPerformed();
296   }
297
298   private void close_actionPerformed()
299   {
300     try
301     {
302       frame.setClosed(true);
303     } catch (java.beans.PropertyVetoException ex)
304     {
305     }
306   }
307
308   /**
309    * Adds widgets to the panel
310    * 
311    * @throws Exception
312    */
313   private void jbInit() throws Exception
314   {
315     this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
316     this.setBackground(Color.white);
317
318     JPanel formatPanel = buildFormatOptionsPanel();
319     JPanel linkedFeatures = buildLinkedFeaturesPanel();
320     JPanel actionsPanel = buildActionsPanel();
321
322     this.add(formatPanel);
323     this.add(linkedFeatures);
324     this.add(actionsPanel);
325   }
326
327   /**
328    * Builds a panel with a checkbox for the option to export linked (CDS/peptide)
329    * features. This is hidden by default, and only made visible if exporting
330    * features from a split frame panel which is configured to show linked
331    * features.
332    * 
333    * @return
334    */
335   private JPanel buildLinkedFeaturesPanel()
336   {
337     linkedFeaturesPanel = new JPanel();
338     linkedFeaturesPanel.setOpaque(false);
339
340     boolean nucleotide = ap.av.isNucleotide();
341     String complement = nucleotide
342             ? MessageManager.getString("label.protein").toLowerCase(Locale.ROOT)
343             : "CDS";
344     JLabel label = new JLabel(
345             MessageManager.formatMessage("label.include_linked_features",
346                     complement));
347     label.setHorizontalAlignment(SwingConstants.TRAILING);
348     String tooltip = MessageManager
349             .formatMessage("label.include_linked_tooltip", complement);
350     label.setToolTipText(
351             JvSwingUtils.wrapTooltip(true, tooltip));
352
353     includeLinkedFeatures = new JCheckBox();
354     linkedFeaturesPanel.add(label);
355     linkedFeaturesPanel.add(includeLinkedFeatures);
356     linkedFeaturesPanel.setVisible(false);
357
358     return linkedFeaturesPanel;
359   }
360
361   /**
362    * Builds the panel with to File or Textbox or Close actions
363    * 
364    * @return
365    */
366   JPanel buildActionsPanel()
367   {
368     JPanel actionsPanel = new JPanel();
369     actionsPanel.setOpaque(false);
370
371     JButton toFile = new JButton(MessageManager.getString("label.to_file"));
372     toFile.addActionListener(new ActionListener()
373     {
374       @Override
375       public void actionPerformed(ActionEvent e)
376       {
377         toFile_actionPerformed();
378       }
379     });
380     JButton toTextbox = new JButton(
381             MessageManager.getString("label.to_textbox"));
382     toTextbox.addActionListener(new ActionListener()
383     {
384       @Override
385       public void actionPerformed(ActionEvent e)
386       {
387         toTextbox_actionPerformed();
388       }
389     });
390     JButton close = new JButton(MessageManager.getString("action.close"));
391     close.addActionListener(new ActionListener()
392     {
393       @Override
394       public void actionPerformed(ActionEvent e)
395       {
396         close_actionPerformed();
397       }
398     });
399
400     actionsPanel.add(toFile);
401     actionsPanel.add(toTextbox);
402     actionsPanel.add(close);
403
404     return actionsPanel;
405   }
406
407   /**
408    * Builds the panel with options to output in Jalview, GFF or CSV format. GFF is
409    * only made visible when exporting features, CSV only when exporting
410    * annotation.
411    * 
412    * @return
413    */
414   JPanel buildFormatOptionsPanel()
415   {
416     JPanel formatPanel = new JPanel();
417     // formatPanel.setBorder(BorderFactory.createEtchedBorder());
418     formatPanel.setOpaque(false);
419
420     JRadioButton jalviewFormat = new JRadioButton("Jalview");
421     jalviewFormat.setOpaque(false);
422     jalviewFormat.setSelected(true);
423     GFFFormat.setOpaque(false);
424     GFFFormat.setText("GFF");
425     CSVFormat.setOpaque(false);
426     CSVFormat.setText(MessageManager.getString("label.csv_spreadsheet"));
427
428     ButtonGroup buttonGroup = new ButtonGroup();
429     buttonGroup.add(jalviewFormat);
430     buttonGroup.add(GFFFormat);
431     buttonGroup.add(CSVFormat);
432
433     JLabel format = new JLabel(
434             MessageManager.getString("action.format") + " ");
435     format.setHorizontalAlignment(SwingConstants.TRAILING);
436
437     formatPanel.add(format);
438     formatPanel.add(jalviewFormat);
439     formatPanel.add(GFFFormat);
440     formatPanel.add(CSVFormat);
441
442     return formatPanel;
443   }
444 }