Xcos: fix recent diagrams management
[scilab.git] / scilab / modules / xcos / src / java / org / scilab / modules / xcos / actions / ExportAllAction.java
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2009 - DIGITEO - Vincent COUVERT
4  * Copyright (C) 2010 - DIGITEO - Clement DAVID
5  * Copyright (C) 2011-2015 - Scilab Enterprises - Clement DAVID
6  *
7  * Copyright (C) 2012 - 2016 - Scilab Enterprises
8  *
9  * This file is hereby licensed under the terms of the GNU GPL v2.0,
10  * pursuant to article 5.3.4 of the CeCILL v.2.1.
11  * This file was originally licensed under the terms of the CeCILL v2.1,
12  * and continues to be available under such terms.
13  * For more information, see the COPYING file which you should have received
14  * along with this program.
15  *
16  */
17
18 package org.scilab.modules.xcos.actions;
19
20 import java.awt.Color;
21 import java.awt.Toolkit;
22 import java.awt.event.ActionEvent;
23 import java.awt.image.BufferedImage;
24 import java.io.File;
25 import java.io.IOException;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collection;
29 import java.util.Set;
30 import java.util.TreeSet;
31
32 import javax.imageio.ImageIO;
33 import javax.swing.JFileChooser;
34 import javax.swing.JOptionPane;
35
36 import org.scilab.modules.graph.ScilabGraph;
37 import org.scilab.modules.graph.actions.base.DefaultAction;
38 import org.scilab.modules.graph.utils.ScilabGraphRenderer;
39 import org.scilab.modules.gui.bridge.filechooser.FileMask;
40 import org.scilab.modules.gui.menuitem.MenuItem;
41 import org.scilab.modules.gui.messagebox.ScilabModalDialog;
42 import org.scilab.modules.gui.messagebox.ScilabModalDialog.AnswerOption;
43 import org.scilab.modules.gui.messagebox.ScilabModalDialog.ButtonType;
44 import org.scilab.modules.gui.messagebox.ScilabModalDialog.IconType;
45 import org.scilab.modules.xcos.JavaController;
46 import org.scilab.modules.xcos.Kind;
47 import org.scilab.modules.xcos.ObjectProperties;
48 import org.scilab.modules.xcos.VectorOfScicosID;
49 import org.scilab.modules.xcos.Xcos;
50 import org.scilab.modules.xcos.XcosTab;
51 import org.scilab.modules.xcos.configuration.ConfigurationManager;
52 import org.scilab.modules.xcos.graph.XcosDiagram;
53 import org.scilab.modules.xcos.utils.XcosMessages;
54 import org.w3c.dom.Document;
55
56 import com.mxgraph.swing.mxGraphComponent;
57 import com.mxgraph.util.mxCellRenderer;
58 import com.mxgraph.util.mxUtils;
59 import com.mxgraph.util.mxXmlUtils;
60
61 /**
62  * Diagram export management
63  */
64 @SuppressWarnings(value = { "serial" })
65 public final class ExportAllAction extends DefaultAction {
66     /** Name of the action */
67     public static final String NAME = XcosMessages.EXPORT_ALL;
68     /** Icon name of the action */
69     public static final String SMALL_ICON = "";
70     /** Mnemonic key of the action */
71     public static final int MNEMONIC_KEY = 0;
72     /** Accelerator key for the action */
73     public static final int ACCELERATOR_KEY = Toolkit.getDefaultToolkit()
74             .getMenuShortcutKeyMask();
75
76     private static final String HTML = "html";
77     private static final String VML = "vml";
78     private static final String SVG = "svg";
79
80     private boolean useBackground = true;
81
82     /**
83      * Constructor
84      *
85      * @param scilabGraph
86      *            associated Scilab Graph
87      */
88     public ExportAllAction(ScilabGraph scilabGraph) {
89         super(scilabGraph);
90     }
91
92     /**
93      * Create export menu
94      *
95      * @param scilabGraph
96      *            associated Scilab Graph
97      * @return the menu
98      */
99     public static MenuItem createMenu(ScilabGraph scilabGraph) {
100         return createMenu(scilabGraph, ExportAllAction.class);
101     }
102
103     /**
104      * Action !!!
105      *
106      * @param e
107      *            parameter
108      * @see org.scilab.modules.graph.actions.base.DefaultAction#actionPerformed(java.awt.event.ActionEvent)
109      */
110     @Override
111     public void actionPerformed(ActionEvent e) {
112         final XcosDiagram graph = ((XcosDiagram) getGraph(null)).getRootDiagram();
113
114         // Adds a filter for each supported image format
115         Collection<String> imageFormats = Arrays.asList(ImageIO.getWriterFileSuffixes());
116
117         // The mask ordered collection
118         Set<String> mask = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
119
120         mask.add(SVG);
121         mask.add(HTML);
122         mask.add(VML);
123         mask.addAll(imageFormats);
124
125         JFileChooser fc = new JFileChooser();
126         fc.setDialogTitle(XcosMessages.EXPORT_ALL + XcosMessages.DOTS);
127         fc.setApproveButtonText(XcosMessages.EXPORT);
128         fc.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
129
130         fc.setAcceptAllFileFilterUsed(false);
131         for (String string : mask) {
132             fc.addChoosableFileFilter(new FileMask(string, string.toUpperCase()));
133         }
134
135         ConfigurationManager.configureCurrentDirectory(fc);
136
137         int selection = fc.showSaveDialog(getGraph(null).getAsComponent());
138         if (selection == JFileChooser.APPROVE_OPTION) {
139             File dir = fc.getSelectedFile();
140
141             /* getting the format */
142             String format = ((FileMask) fc.getFileFilter()).getExtensionFromFilter();
143
144             /* update states from the format */
145             if ((!format.equalsIgnoreCase("png"))
146                     || ScilabModalDialog.show(XcosTab.get((XcosDiagram) getGraph(null)),
147                                               XcosMessages.TRANSPARENT_BACKGROUND, XcosMessages.XCOS,
148                                               IconType.QUESTION_ICON, ButtonType.YES_NO) != AnswerOption.YES_OPTION) {
149                 useBackground = true;
150             }
151
152             /*
153              * Instantiate all the sub-diagrams
154              */
155             JavaController controller = new JavaController();
156             ArrayList<XcosDiagram> diagrams = new ArrayList<>();
157             diagrams.add(graph);
158
159             ArrayList<Long> stash = new ArrayList<>();
160             allocateDiagrams(controller, diagrams, stash, graph.getUID(), Kind.DIAGRAM);
161             while (!stash.isEmpty()) {
162                 final long uid = stash.remove(stash.size() - 1);
163                 allocateDiagrams(controller, diagrams, stash, uid, Kind.BLOCK);
164             }
165
166             /*
167              * Export
168              */
169             try {
170                 export(graph, new File(dir, graph.getTitle() + "." + format), format);
171
172                 for (XcosDiagram d : diagrams) {
173                     export(d, new File(dir, d.getTitle() + "." + format), format);
174                 }
175             } catch (IOException e1) {
176                 e1.printStackTrace();
177             }
178
179         }
180     }
181
182     private void allocateDiagrams(JavaController controller, ArrayList<XcosDiagram> diagrams, ArrayList<Long> stash,
183                                   final long uid, final Kind kind) {
184         final VectorOfScicosID children = new VectorOfScicosID();
185         controller.getObjectProperty(uid, kind, ObjectProperties.CHILDREN, children);
186
187         final int len = children.size();
188         for (int i = 0; i < len ; i++) {
189             String[] interfaceFunction = new String[1];
190             long currentUID = children.get(i);
191             if (controller.getKind(currentUID) == Kind.BLOCK) {
192                 controller.getObjectProperty(children.get(i), Kind.BLOCK, ObjectProperties.INTERFACE_FUNCTION, interfaceFunction);
193                 if (!"SUPER_f".equals(interfaceFunction[0])) {
194                     continue;
195                 }
196
197
198                 if (diagrams.stream().noneMatch(d -> d.getUID() == currentUID)) {
199                     String[] strUID = new String[1];
200                     controller.getObjectProperty(currentUID, Kind.BLOCK, ObjectProperties.UID, strUID);
201
202                     final XcosDiagram child = new XcosDiagram(controller, currentUID, Kind.BLOCK, strUID[0]);
203                     diagrams.add(child);
204                     stash.add(currentUID);
205                 }
206             }
207
208         }
209     }
210
211     /**
212      * Export the graph into the filename.
213      *
214      * The filename extension is used find export format.
215      *
216      * @param graph
217      *            the current graph
218      * @param filename
219      *            the filename
220      * @param fileFormat
221      *            the format to save
222      * @throws IOException
223      *             when a write problem occurs.
224      */
225     private void export(XcosDiagram graph, File filename, String fileFormat)
226     throws IOException {
227         filename.getParentFile().mkdirs();
228
229         if (fileFormat.equalsIgnoreCase(SVG)) {
230             ScilabGraphRenderer.createSvgDocument(graph, null, 1, null, null,
231                                                   filename.getCanonicalPath());
232         } else if (fileFormat.equalsIgnoreCase(VML)) {
233             Document doc = mxCellRenderer.createVmlDocument(graph, null, 1,
234                            null, null);
235             if (doc != null) {
236                 mxUtils.writeFile(mxXmlUtils.getXml(doc.getDocumentElement()),
237                                   filename.getCanonicalPath());
238             }
239         } else if (fileFormat.equalsIgnoreCase(HTML)) {
240             Document doc = mxCellRenderer.createHtmlDocument(graph, null, 1,
241                            null, null);
242             if (doc != null) {
243                 mxUtils.writeFile(mxXmlUtils.getXml(doc.getDocumentElement()),
244                                   filename.getCanonicalPath());
245             }
246         } else {
247             exportBufferedImage(graph, filename, fileFormat);
248         }
249     }
250
251     /**
252      * Use the Java image capabilities to export the diagram
253      *
254      * @param graph
255      *            the current diagram
256      * @param filename
257      *            the current filename
258      * @param fileFormat
259      *            the file format
260      * @throws IOException
261      *             when an error occurs
262      */
263     private void exportBufferedImage(XcosDiagram graph, File filename,
264                                      String fileFormat) throws IOException {
265         final mxGraphComponent graphComponent = graph.getAsComponent();
266
267         Color bg = null;
268
269         if (useBackground) {
270             bg = graphComponent.getBackground();
271         }
272
273         BufferedImage image = mxCellRenderer.createBufferedImage(graph, null,
274                               1, bg, graphComponent.isAntiAlias(), null,
275                               graphComponent.getCanvas());
276
277         if (image != null) {
278             ImageIO.write(image, fileFormat, filename);
279         } else {
280             JOptionPane.showMessageDialog(graphComponent,
281                                           XcosMessages.NO_IMAGE_DATA);
282         }
283     }
284 }