001    /*
002     * Copyright 2002 - 2007 JEuclid, http://jeuclid.sf.net
003     * 
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    /* $Id: FileIO.java,v cca61eec2241 2008/05/23 09:53:47 maxberger $ */
018    
019    package net.sourceforge.jeuclid.app.mathviewer;
020    
021    import java.awt.FileDialog;
022    import java.awt.Frame;
023    import java.io.File;
024    import java.io.FilenameFilter;
025    import java.io.IOException;
026    import java.util.Set;
027    
028    import javax.swing.JFileChooser;
029    import javax.swing.JOptionPane;
030    
031    import net.sourceforge.jeuclid.MathMLParserSupport;
032    import net.sourceforge.jeuclid.MutableLayoutContext;
033    import net.sourceforge.jeuclid.converter.Converter;
034    import net.sourceforge.jeuclid.converter.ConverterRegistry;
035    
036    import org.apache.commons.logging.Log;
037    import org.apache.commons.logging.LogFactory;
038    import org.w3c.dom.Document;
039    import org.w3c.dom.Node;
040    import org.xml.sax.SAXException;
041    
042    /**
043     * File I/O support functionality for MathViewer.
044     * 
045     * @version $Revision: cca61eec2241 $
046     */
047    public final class FileIO {
048    
049        /**
050         * Logger for this class
051         */
052        private static final Log LOGGER = LogFactory.getLog(FileIO.class);
053    
054        private static final String EXPORT_ERROR = "MathViewer.exportError"; //$NON-NLS-1$,
055    
056        private File lastPath;
057    
058        private static final class SingletonHolder {
059            private static FileIO instance = new FileIO();
060    
061            private SingletonHolder() {
062            }
063        }
064    
065        private FileIO() {
066        }
067    
068        /**
069         * Retrieve the FileIO object.
070         * 
071         * @return the FileIO object
072         */
073        public static FileIO getInstance() {
074            return FileIO.SingletonHolder.instance;
075        }
076    
077        private static String getExtension(final String fileName) {
078            return fileName.substring(fileName.lastIndexOf('.') + 1);
079        }
080    
081        private static class SaveExportFilter implements FilenameFilter {
082    
083            private final Set<String> extensions;
084    
085            protected SaveExportFilter() {
086                this.extensions = ConverterRegistry.getInstance()
087                        .getAvailableExtensions();
088            };
089    
090            public boolean accept(final File dir, final String name) {
091                return this.extensions.contains(FileIO.getExtension(name));
092            }
093        }
094    
095        /**
096         * Select a file.
097         * 
098         * @param parent
099         *            Frame of the parent
100         * @return A File or null.
101         */
102        public File selectFileToOpen(final Frame parent) {
103            final File selectedFile;
104    
105            if (MathViewer.OSX) {
106                // Have to use AWT file chooser for Mac-friendlyness
107                final FileDialog chooser = new FileDialog(parent,
108                        "Please select a MathML file");
109                if (this.lastPath != null) {
110                    chooser.setDirectory(this.lastPath.toString());
111                }
112                chooser.setVisible(true);
113                final String fileName = chooser.getFile();
114                if (fileName != null) {
115                    selectedFile = new File(chooser.getDirectory(), fileName);
116                } else {
117                    selectedFile = null;
118                }
119            } else {
120                final JFileChooser fc = new JFileChooser(this.lastPath);
121                final int returnVal = fc.showOpenDialog(parent);
122                if (returnVal == JFileChooser.APPROVE_OPTION) {
123                    selectedFile = fc.getSelectedFile();
124                } else {
125                    selectedFile = null;
126                }
127            }
128            if (selectedFile != null) {
129                this.lastPath = selectedFile.getParentFile();
130            }
131            return selectedFile;
132        }
133    
134        /**
135         * Load the given file.
136         * 
137         * @param selectedFile
138         *            File object to load.
139         * @param parent
140         *            Frame of parent window
141         * @return a parsed Document or null
142         */
143        public Document loadFile(final Frame parent, final File selectedFile) {
144            Document retVal;
145            if (selectedFile == null) {
146                retVal = null;
147            } else {
148                try {
149                    retVal = MathMLParserSupport.parseFile(selectedFile);
150                } catch (final SAXException e) {
151                    retVal = null;
152                    FileIO.LOGGER.warn(e.getMessage(), e);
153                    JOptionPane
154                            .showMessageDialog(
155                                    parent,
156                                    e.getMessage(),
157                                    Messages.getString("MathViewer.errorParsing"), JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
158                } catch (final IOException e) {
159                    retVal = null;
160                    FileIO.LOGGER.warn(e.getMessage(), e);
161                    JOptionPane
162                            .showMessageDialog(
163                                    parent,
164                                    e.getMessage(),
165                                    Messages
166                                            .getString("MathViewer.errorAccessing"), JOptionPane.ERROR_MESSAGE); //$NON-NLS-1$
167                }
168            }
169            return retVal;
170        }
171    
172        /**
173         * Save a document.
174         * 
175         * @param parent
176         *            frame of parent.
177         * @param document
178         *            the MML document to save.
179         * @param params
180         *            rendering parameters.
181         */
182        public void saveDocument(final Frame parent, final Node document,
183                final MutableLayoutContext params) {
184            final File selectedFile;
185    
186            if (MathViewer.OSX) {
187                // Have to use AWT file chooser for Mac-friendlyness
188                final FileDialog chooser = new FileDialog(parent, "Export to...",
189                        FileDialog.SAVE);
190                if (this.lastPath != null) {
191                    chooser.setDirectory(this.lastPath.toString());
192                }
193                chooser.setFilenameFilter(new SaveExportFilter());
194    
195                chooser.setVisible(true);
196                final String fileName = chooser.getFile();
197                if (fileName != null) {
198                    selectedFile = new File(chooser.getDirectory(), fileName);
199                } else {
200                    selectedFile = null;
201                }
202            } else {
203                final JFileChooser fc = new JFileChooser(this.lastPath);
204                final int returnVal = fc.showSaveDialog(parent);
205                if (returnVal == JFileChooser.APPROVE_OPTION) {
206                    selectedFile = fc.getSelectedFile();
207                } else {
208                    selectedFile = null;
209                }
210    
211            }
212            if (selectedFile != null) {
213                this.lastPath = selectedFile.getParentFile();
214    
215                FileIO.LOGGER.info(selectedFile);
216    
217                int doIt = JOptionPane.YES_OPTION;
218    
219                if (selectedFile.exists()) {
220                    doIt = JOptionPane.showConfirmDialog(parent, "File "
221                            + selectedFile.getName()
222                            + " already exists. Overwrite?", "Confirm Overwrite",
223                            JOptionPane.YES_NO_OPTION);
224                }
225    
226                if (doIt == JOptionPane.YES_OPTION) {
227                    this.exportAs(parent, selectedFile, document, params);
228                }
229            }
230        }
231    
232        private void exportAs(final Frame parent, final File selectedFile,
233                final Node document, final MutableLayoutContext params) {
234            final String fileName = selectedFile.getName();
235            final String extension = FileIO.getExtension(fileName);
236            final String mimetype = ConverterRegistry.getInstance()
237                    .getMimeTypeForSuffix(extension);
238            if (mimetype != null) {
239                try {
240                    if (Converter.getInstance().convert(document, selectedFile,
241                            mimetype, params) == null) {
242                        JOptionPane.showMessageDialog(parent,
243                                "Failed to write to " + fileName, Messages
244                                        .getString(FileIO.EXPORT_ERROR),
245                                JOptionPane.ERROR_MESSAGE);
246    
247                    }
248                } catch (final IOException e) {
249                    FileIO.LOGGER.warn(e);
250                    JOptionPane.showMessageDialog(parent, e.getMessage(),
251                            Messages.getString(FileIO.EXPORT_ERROR),
252                            JOptionPane.ERROR_MESSAGE);
253                }
254            } else {
255                JOptionPane.showMessageDialog(parent,
256                        "Unsupported file extension " + extension, Messages
257                                .getString(FileIO.EXPORT_ERROR),
258                        JOptionPane.ERROR_MESSAGE);
259    
260            }
261        }
262    
263    }