org.docx4all.ui.menu.FileMenu.java Source code

Java tutorial

Introduction

Here is the source code for org.docx4all.ui.menu.FileMenu.java

Source

/*
 *  Copyright 2007, Plutext Pty Ltd.
 *   
 *  This file is part of Docx4all.
    
Docx4all is free software: you can redistribute it and/or modify
it under the terms of version 3 of the GNU General Public License 
as published by the Free Software Foundation.
    
Docx4all is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License   
along with Docx4all.  If not, see <http://www.gnu.org/licenses/>.
    
 */

package org.docx4all.ui.menu;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;

import javax.swing.JEditorPane;
import javax.swing.JInternalFrame;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileSystemView;
import javax.swing.text.Document;
import javax.swing.text.EditorKit;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import net.sf.vfsjfilechooser.VFSJFileChooser;
import net.sf.vfsjfilechooser.VFSJFileChooser.RETURN_TYPE;
import net.sf.vfsjfilechooser.VFSJFileChooser.SELECTION_MODE;
import net.sf.vfsjfilechooser.accessories.DefaultAccessoriesPanel;
import net.sf.vfsjfilechooser.utils.VFSUtils;

import org.apache.commons.vfs.FileObject;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.provider.UriParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.docx4all.swing.NewShareDialog;
import org.docx4all.swing.PDFViewer;
import org.docx4all.swing.WordMLTextPane;
import org.docx4all.swing.text.DocumentElement;
import org.docx4all.swing.text.WordMLDocument;
import org.docx4all.swing.text.WordMLDocumentFilter;
import org.docx4all.swing.text.WordMLEditorKit;
import org.docx4all.ui.main.Constants;
import org.docx4all.ui.main.ToolBarStates;
import org.docx4all.ui.main.WordMLEditor;
import org.docx4all.util.DocUtil;
import org.docx4all.util.PreferenceUtil;
import org.docx4all.util.SwingUtil;
import org.docx4all.util.XmlUtil;
import org.docx4all.vfs.FileNameExtensionFilter;
import org.docx4all.xml.DocumentML;
import org.docx4all.xml.ElementML;
import org.docx4j.XmlUtils;
import org.docx4j.convert.in.FlatOpcXmlImporter;
import org.docx4j.convert.out.flatOpcXml.FlatOpcXmlCreator;
import org.docx4j.convert.out.html.AbstractHtmlExporter;
//import org.docx4j.convert.out.html.HtmlExporter;
import org.docx4j.convert.out.html.HtmlExporterNG2;
import org.docx4j.convert.out.html.AbstractHtmlExporter.HtmlSettings;
import org.docx4j.convert.out.pdf.PdfConversion;
import org.docx4j.convert.out.pdf.viaXSLFO.PdfSettings;
import org.docx4j.jaxb.Context;
import org.docx4j.jaxb.NamespacePrefixMapperUtils;
import org.docx4j.openpackaging.exceptions.Docx4JException;
import org.docx4j.openpackaging.io.SaveToVFSZipFile;
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;

/**
 *   @author Jojada Tirtowidjojo - 27/11/2007
 */
public class FileMenu extends UIMenu {
    private static Logger log = LoggerFactory.getLogger(FileMenu.class);

    private final static FileMenu _instance = new FileMenu();

    /**
     * The binding key used for this FileMenu object 
     * when passed into scripting environment
     */
    public final static String SCRIPT_BINDING_KEY = "fileMenu:org.docx4all.ui.menu.FileMenu";

    //==========
    //MENU Names
    //==========
    //Used as an argument to JMenu.setName().
    //Therefore it can be used in .properties file 
    //to configure File Menu property in the menu bar
    /**
     * The name of JMenu object that hosts File menu in the menu bar
     */
    public final static String FILE_MENU_NAME = "fileMenu";

    //============
    //ACTION Names
    //============
    //The string value of each action name must be the same as 
    //the method name annotated by @Action tag.
    //Action name is used to configure Menu/Button Action property
    //in .properties file and get an Action object out of 
    //Spring Application Framework

    /**
     * The action name of New file menu
     */
    public final static String NEW_FILE_ACTION_NAME = "newFile";

    /**
     * The action name of Open file menu
     */
    public final static String OPEN_FILE_ACTION_NAME = "openFile";

    /**
     * The action name of Save file menu
     */
    public final static String SAVE_FILE_ACTION_NAME = "saveFile";

    /**
     * The action name of Save As file menu
     */
    public final static String SAVE_AS_DOCX_ACTION_NAME = "saveAsDocx";

    /**
     * The action name of Save As file menu
     */
    public final static String SAVE_ALL_FILES_ACTION_NAME = "saveAllFiles";

    /**
     * The action name of Export As Html menu
     */
    public final static String EXPORT_AS_HTML_ACTION_NAME = "exportAsHtml";

    /**
     * The action name of Save As Shared Document menu
     */
    public final static String EXPORT_AS_SHARED_DOC_ACTION_NAME = "exportAsSharedDoc";

    /**
     * The action name of Export As Non Shared Document menu
     */
    public final static String EXPORT_AS_NON_SHARED_DOC_ACTION_NAME = "exportAsNonSharedDoc";

    /**
     * The action name of Print Preview menu
     */
    public final static String PRINT_PREVIEW_ACTION_NAME = "printPreview";

    /**
     * The action name of Close menu
     */
    public final static String CLOSE_FILE_ACTION_NAME = "closeFile";

    /**
     * The action name of Close All menu
     */
    public final static String CLOSE_ALL_FILES_ACTION_NAME = "closeAllFiles";

    /**
     * The action name of Exit menu
     */
    public final static String EXIT_ACTION_NAME = "exit";

    private static final String[] _menuItemActionNames = { NEW_FILE_ACTION_NAME, OPEN_FILE_ACTION_NAME,
            SEPARATOR_CODE, SAVE_FILE_ACTION_NAME, SAVE_AS_DOCX_ACTION_NAME, SAVE_ALL_FILES_ACTION_NAME,
            SEPARATOR_CODE, EXPORT_AS_HTML_ACTION_NAME, EXPORT_AS_SHARED_DOC_ACTION_NAME,
            EXPORT_AS_NON_SHARED_DOC_ACTION_NAME, SEPARATOR_CODE, PRINT_PREVIEW_ACTION_NAME, SEPARATOR_CODE,
            CLOSE_FILE_ACTION_NAME, CLOSE_ALL_FILES_ACTION_NAME, SEPARATOR_CODE, EXIT_ACTION_NAME };

    public static FileMenu getInstance() {
        return _instance;
    }

    private short _untitledFileNumber = 0;

    private FileMenu() {
        ;//singleton
    }

    public String[] getMenuItemActionNames() {
        String[] names = new String[_menuItemActionNames.length];
        System.arraycopy(_menuItemActionNames, 0, names, 0, _menuItemActionNames.length);
        return names;
    }

    public String getMenuName() {
        return FILE_MENU_NAME;
    }

    protected JMenuItem createMenuItem(String actionName) {
        JMenuItem theItem = super.createMenuItem(actionName);

        WordMLEditor editor = WordMLEditor.getInstance(WordMLEditor.class);
        ToolBarStates toolbarStates = editor.getToolbarStates();

        if (SAVE_FILE_ACTION_NAME.equals(actionName) || SAVE_AS_DOCX_ACTION_NAME.equals(actionName)) {
            theItem.setEnabled(false);
            toolbarStates.addPropertyChangeListener(ToolBarStates.DOC_DIRTY_PROPERTY_NAME,
                    new EnableOnEqual(theItem, Boolean.TRUE));

        } else if (SAVE_ALL_FILES_ACTION_NAME.equals(actionName)) {
            theItem.setEnabled(false);
            toolbarStates.addPropertyChangeListener(ToolBarStates.ANY_DOC_DIRTY_PROPERTY_NAME,
                    new EnableOnEqual(theItem, Boolean.TRUE));

        } else if (EXPORT_AS_SHARED_DOC_ACTION_NAME.equals(actionName)) {
            theItem.setEnabled(false);
            toolbarStates.addPropertyChangeListener(ToolBarStates.DOC_SHARED_PROPERTY_NAME,
                    new DisableOnEqual(theItem, Boolean.TRUE));

        } else if (EXPORT_AS_NON_SHARED_DOC_ACTION_NAME.equals(actionName)) {
            theItem.setEnabled(false);
            toolbarStates.addPropertyChangeListener(ToolBarStates.DOC_SHARED_PROPERTY_NAME,
                    new EnableOnEqual(theItem, Boolean.TRUE));

        } else if (PRINT_PREVIEW_ACTION_NAME.equals(actionName) || EXPORT_AS_HTML_ACTION_NAME.equals(actionName)
                || CLOSE_FILE_ACTION_NAME.equals(actionName) || CLOSE_ALL_FILES_ACTION_NAME.equals(actionName)) {
            theItem.setEnabled(false);
            toolbarStates.addPropertyChangeListener(ToolBarStates.IFRAME_NUMBERS_PROPERTY_NAME,
                    new EnableOnPositive(theItem));
        }

        return theItem;
    }

    @Action
    public void newFile() {
        Preferences prefs = Preferences.userNodeForPackage(getClass());
        WordMLEditor editor = WordMLEditor.getInstance(WordMLEditor.class);

        FileObject fo = null;
        try {
            //Prepare the new file name
            StringBuffer newFile = new StringBuffer();
            newFile.append(editor.getUntitledFileName());
            newFile.append(++_untitledFileNumber);
            newFile.append(".docx");

            //put new file in same directory as last opened local file's.
            //if there isn't last opened local file, put it in the
            //swing file chooser's default directory.
            String lastFile = prefs.get(Constants.LAST_OPENED_LOCAL_FILE, Constants.EMPTY_STRING);
            if (lastFile.length() == 0) {
                fo = VFSUtils.getFileSystemManager()
                        .toFileObject(FileSystemView.getFileSystemView().getDefaultDirectory());
            } else {
                fo = VFSUtils.getFileSystemManager().resolveFile(lastFile).getParent();
            }
            fo = fo.resolveFile(newFile.toString());

        } catch (FileSystemException exc) {
            exc.printStackTrace();
            ResourceMap rm = editor.getContext().getResourceMap(getClass());
            String title = rm.getString(FileMenu.NEW_FILE_ACTION_NAME + ".Action.text");
            String message = rm.getString(FileMenu.NEW_FILE_ACTION_NAME + ".Action.errorMessage");
            editor.showMessageDialog(title, message, JOptionPane.INFORMATION_MESSAGE);
            return;
        }

        editor.createInternalFrame(fo);
    }

    @Action
    public void exportAsSharedDoc(ActionEvent actionEvent) {
        WordMLEditor editor = WordMLEditor.getInstance(WordMLEditor.class);
        JEditorPane view = editor.getCurrentEditor();
        if (view instanceof WordMLTextPane) {
            WordMLTextPane wmlTextPane = (WordMLTextPane) view;
            WordMLDocument doc = (WordMLDocument) wmlTextPane.getDocument();
            if (DocUtil.getChunkingStrategy(doc) == null) {
                displaySetupFirstMessage();
                return;
            }

            NewShareDialog d = new NewShareDialog(editor.getWindowFrame());
            d.pack();
            d.setLocationRelativeTo(editor.getWindowFrame());
            d.setVisible(true);
            if (d.getValue() == NewShareDialog.NEXT_BUTTON_TEXT) {
                DocumentElement root = (DocumentElement) doc.getDefaultRootElement();
                DocumentML docML = (DocumentML) root.getElementML();
                WordprocessingMLPackage wmlPackage = docML.getWordprocessingMLPackage();
                XmlUtil.setPlutextCheckinMessageEnabledProperty(wmlPackage, d.isCommentOnEveryChange());

                RETURN_TYPE val = saveAsFile(EXPORT_AS_SHARED_DOC_ACTION_NAME, actionEvent, Constants.DOCX_STRING);

                Cursor origCursor = wmlTextPane.getCursor();
                wmlTextPane.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));

                if (val != RETURN_TYPE.APPROVE) {
                    //Cancelled or Error
                    XmlUtil.removePlutextProperty(wmlPackage,
                            Constants.PLUTEXT_CHECKIN_MESSAGE_ENABLED_PROPERTY_NAME);

                } else if (!DocUtil.isSharedDocument(doc)) {
                    //Because user has saved to places other than predefined server.
                    XmlUtil.removeSharedDocumentProperties(wmlPackage);
                    //TODO: Display a message saying a shared document can only
                    //be created in predefined server and ask user to try again.
                } else {

                    String filepath = (String) doc.getProperty(WordMLDocument.FILE_PATH_PROPERTY);
                    try {
                        FileObject fo = VFSUtils.getFileSystemManager().resolveFile(filepath);
                        doc = wmlTextPane.getWordMLEditorKit().read(fo);

                        doc.putProperty(WordMLDocument.FILE_PATH_PROPERTY, filepath);
                        doc.addDocumentListener(editor.getToolbarStates());
                        doc.setDocumentFilter(new WordMLDocumentFilter());

                        wmlTextPane.setDocument(doc);
                        wmlTextPane.putClientProperty(Constants.LOCAL_VIEWS_SYNCHRONIZED_FLAG, Boolean.TRUE);

                        if (DocUtil.isSharedDocument(doc)) {
                            wmlTextPane.getWordMLEditorKit().initPlutextClient(wmlTextPane);
                        }
                    } catch (IOException exc) {
                        exc.printStackTrace();
                        //TODO:Display an IO error message and ask user to close the document
                        //and try to reopen it.
                    }

                }

                wmlTextPane.setCursor(origCursor);
            }
            d.dispose();
        }
    }

    private void displaySetupFirstMessage() {
        WordMLEditor editor = WordMLEditor.getInstance(WordMLEditor.class);
        ResourceMap rm = editor.getContext().getResourceMap(getClass());
        String title = rm.getString("exportAsSharedDoc.Action.text");
        String message = rm.getString("exportAsSharedDoc.Action.setupFirstMessage");
        editor.showMessageDialog(title, message, JOptionPane.INFORMATION_MESSAGE);
    }

    @Action
    public void exportAsNonSharedDoc(ActionEvent actionEvent) {
        WordMLEditor editor = WordMLEditor.getInstance(WordMLEditor.class);
        JEditorPane view = editor.getCurrentEditor();
        if (view instanceof WordMLTextPane) {
            WordMLTextPane textpane = (WordMLTextPane) view;
            WordMLDocument doc = (WordMLDocument) textpane.getDocument();
            if (DocUtil.isSharedDocument(doc)) {
                textpane.saveCaretText();
                saveAsFile(EXPORT_AS_NON_SHARED_DOC_ACTION_NAME, actionEvent, Constants.DOCX_STRING);
            }
        }
    }

    @Action
    public void openFile(ActionEvent actionEvent) {
        Preferences prefs = Preferences.userNodeForPackage(getClass());
        WordMLEditor editor = WordMLEditor.getInstance(WordMLEditor.class);
        ResourceMap rm = editor.getContext().getResourceMap(WordMLEditor.class);

        String lastFileUri = prefs.get(Constants.LAST_OPENED_FILE, Constants.EMPTY_STRING);
        FileObject dir = null;
        if (lastFileUri.length() > 0) {
            try {
                dir = VFSUtils.getFileSystemManager().resolveFile(lastFileUri).getParent();
            } catch (FileSystemException exc) {
                dir = null;
            }
        }

        VFSJFileChooser chooser = createFileChooser(rm, dir, Constants.DOCX_STRING);

        RETURN_TYPE returnVal = chooser.showOpenDialog((Component) actionEvent.getSource());

        if (returnVal == RETURN_TYPE.APPROVE) {
            FileObject file = getSelectedFile(chooser, Constants.DOCX_STRING);
            if (file != null) {
                lastFileUri = file.getName().getURI();

                prefs.put(Constants.LAST_OPENED_FILE, lastFileUri);
                if (file.getName().getScheme().equals(("file"))) {
                    prefs.put(Constants.LAST_OPENED_LOCAL_FILE, lastFileUri);
                }
                PreferenceUtil.flush(prefs);
                log.info("\n\n Opening " + VFSUtils.getFriendlyName(lastFileUri));
                editor.createInternalFrame(file);
            }
        }
    }

    @Action
    public void saveFile(ActionEvent actionEvent) {
        WordMLEditor editor = WordMLEditor.getInstance(WordMLEditor.class);
        if (editor.getToolbarStates().isDocumentDirty()) {
            JInternalFrame iframe = editor.getCurrentInternalFrame();
            if (iframe.getTitle().startsWith(editor.getUntitledFileName())) {
                saveAsDocx(actionEvent);

            } else {
                WordMLTextPane textPane = SwingUtil.getWordMLTextPane(iframe);
                if (textPane != null && textPane.getWordMLEditorKit().getPlutextClient() != null
                        && editor.getCurrentEditor() != textPane) {

                    ResourceMap rm = editor.getContext().getResourceMap(getClass());
                    String title = rm.getString("saveFile.Action.text");
                    String message = rm.getString("saveFile.Action.goto.editorView.infoMessage");
                    editor.showMessageDialog(title, message, JOptionPane.INFORMATION_MESSAGE);

                    return;
                }

                boolean success = save(iframe, null, SAVE_FILE_ACTION_NAME);
                if (success) {
                    editor.getToolbarStates().setDocumentDirty(iframe, false);
                    editor.getToolbarStates().setLocalEditsEnabled(iframe, false);
                }
            }
        }
    }

    @Action
    public void exportAsHtml(ActionEvent actionEvent) {
        saveAsFile(EXPORT_AS_HTML_ACTION_NAME, actionEvent, Constants.HTML_STRING);
    }

    @Action
    public void saveAsDocx(ActionEvent actionEvent) {
        saveAsFile(SAVE_AS_DOCX_ACTION_NAME, actionEvent, Constants.DOCX_STRING);
    }

    private RETURN_TYPE saveAsFile(String callerActionName, ActionEvent actionEvent, String fileType) {
        Preferences prefs = Preferences.userNodeForPackage(getClass());
        WordMLEditor editor = WordMLEditor.getInstance(WordMLEditor.class);
        ResourceMap rm = editor.getContext().getResourceMap(getClass());

        JInternalFrame iframe = editor.getCurrentInternalFrame();
        String oldFilePath = (String) iframe.getClientProperty(WordMLDocument.FILE_PATH_PROPERTY);

        VFSJFileChooser chooser = createFileChooser(rm, callerActionName, iframe, fileType);

        RETURN_TYPE returnVal = chooser.showSaveDialog((Component) actionEvent.getSource());
        if (returnVal == RETURN_TYPE.APPROVE) {
            FileObject selectedFile = getSelectedFile(chooser, fileType);

            boolean error = false;
            boolean newlyCreatedFile = false;

            if (selectedFile == null) {

                // Should never happen, whether the file exists or not

            } else {

                //Check selectedFile's existence and ask user confirmation when needed.
                try {
                    boolean selectedFileExists = selectedFile.exists();
                    if (!selectedFileExists) {
                        FileObject parent = selectedFile.getParent();
                        String uri = UriParser.decode(parent.getName().getURI());

                        if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") > -1
                                && parent.getName().getScheme().startsWith("file") && !parent.isWriteable()
                                && (uri.indexOf("/Documents") > -1 || uri.indexOf("/My Documents") > -1)) {
                            //TODO: Check whether we still need this workaround.
                            //See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4939819
                            //Re: File.canWrite() returns false for the "My Documents" directory (win)
                            String localpath = org.docx4j.utils.VFSUtils.getLocalFilePath(parent);
                            File f = new File(localpath);
                            f.setWritable(true, true);
                        }

                        selectedFile.createFile();
                        newlyCreatedFile = true;

                    } else if (!selectedFile.getName().getURI().equalsIgnoreCase(oldFilePath)) {
                        String title = rm.getString(callerActionName + ".Action.text");
                        String message = VFSUtils.getFriendlyName(selectedFile.getName().getURI()) + "\n"
                                + rm.getString(callerActionName + ".Action.confirmMessage");
                        int answer = editor.showConfirmDialog(title, message, JOptionPane.YES_NO_OPTION,
                                JOptionPane.QUESTION_MESSAGE);
                        if (answer != JOptionPane.YES_OPTION) {
                            selectedFile = null;
                        }
                    } // if (!selectedFileExists)

                } catch (FileSystemException exc) {
                    exc.printStackTrace();//ignore
                    log.error("Couldn't create new file or assure file existence. File = "
                            + selectedFile.getName().getURI());
                    selectedFile = null;
                    error = true;
                }
            }

            //Check whether there has been an error, cancellation by user
            //or may proceed to saving file.
            if (selectedFile != null) {
                //Proceed to saving file
                String selectedPath = selectedFile.getName().getURI();
                if (log.isDebugEnabled()) {
                    log.debug("saveAsFile(): selectedFile = " + VFSUtils.getFriendlyName(selectedPath));
                }

                prefs.put(Constants.LAST_OPENED_FILE, selectedPath);
                if (selectedFile.getName().getScheme().equals("file")) {
                    prefs.put(Constants.LAST_OPENED_LOCAL_FILE, selectedPath);
                }
                PreferenceUtil.flush(prefs);

                boolean success = false;
                if (EXPORT_AS_NON_SHARED_DOC_ACTION_NAME.equals(callerActionName)) {
                    log.info("saveAsFile(): Exporting as non shared document to "
                            + VFSUtils.getFriendlyName(selectedPath));
                    success = export(iframe, selectedPath, callerActionName);
                    if (success) {
                        prefs.put(Constants.LAST_OPENED_FILE, selectedPath);
                        if (selectedPath.startsWith("file:")) {
                            prefs.put(Constants.LAST_OPENED_LOCAL_FILE, selectedPath);
                        }
                        PreferenceUtil.flush(prefs);
                        log.info("saveAsFile(): Opening " + VFSUtils.getFriendlyName(selectedPath));
                        editor.createInternalFrame(selectedFile);
                    }
                } else {
                    success = save(iframe, selectedPath, callerActionName);
                    if (success) {
                        if (Constants.DOCX_STRING.equals(fileType) || Constants.FLAT_OPC_STRING.equals(fileType)) {
                            //If saving as .docx then update the document dirty flag 
                            //of toolbar states as well as internal frame title.
                            editor.getToolbarStates().setDocumentDirty(iframe, false);
                            editor.getToolbarStates().setLocalEditsEnabled(iframe, false);
                            FileObject file = null;
                            try {
                                file = VFSUtils.getFileSystemManager().resolveFile(oldFilePath);
                                editor.updateInternalFrame(file, selectedFile);
                            } catch (FileSystemException exc) {
                                ;//ignore
                            }
                        } else {
                            //Because document dirty flag is not cleared
                            //and internal frame title is not changed,
                            //we present a success message.
                            String title = rm.getString(callerActionName + ".Action.text");
                            String message = VFSUtils.getFriendlyName(selectedPath) + "\n"
                                    + rm.getString(callerActionName + ".Action.successMessage");
                            editor.showMessageDialog(title, message, JOptionPane.INFORMATION_MESSAGE);
                        }
                    }
                }

                if (!success && newlyCreatedFile) {
                    try {
                        selectedFile.delete();
                    } catch (FileSystemException exc) {
                        log.error("saveAsFile(): Saving failure and cannot remove the newly created file = "
                                + selectedPath);
                        exc.printStackTrace();
                    }
                }
            } else if (error) {
                log.error("saveAsFile(): selectedFile = NULL");
                String title = rm.getString(callerActionName + ".Action.text");
                String message = rm.getString(callerActionName + ".Action.errorMessage");
                editor.showMessageDialog(title, message, JOptionPane.ERROR_MESSAGE);
            }

        } //if (returnVal == JFileChooser.APPROVE_OPTION)

        return returnVal;
    }// saveAsFile()

    /**
     * If user types in a filename JFileChooser does not append the file extension
     * displayed by its FileFilter to it.
     * This method appends desiredFileType parameter as file extension
     * if JFileChooser's selected file does not have it.
     * 
     * @param chooser JFileChooser instance
     * @param desiredFileType File extension
     * @return a File whose extension is desiredFileType.
     */
    public FileObject getSelectedFile(VFSJFileChooser chooser, String desiredFileType) {
        FileObject theFile = chooser.getSelectedFile();

        StringBuffer uri = new StringBuffer(theFile.getName().getURI());
        if (desiredFileType.equalsIgnoreCase(theFile.getName().getExtension())) {
            //user may type in the file extension in the JFileChooser dialog.
            //Therefore worth checking file extension case insensitively
            //          int dot = uri.lastIndexOf(Constants.DOT);
            //          uri = new StringBuffer(uri.substring(0, dot));

            // Do nothing

        } else if (Constants.DOCX_STRING.equals(desiredFileType) // also allow .xml
                && Constants.FLAT_OPC_STRING.equalsIgnoreCase(theFile.getName().getExtension())) {

            // Do nothing

        } else {
            uri.append(Constants.DOT);
            uri.append(desiredFileType);
        }
        try {
            theFile = VFSUtils.getFileSystemManager().resolveFile(uri.toString());
        } catch (FileSystemException exc) {
            exc.printStackTrace();
            theFile = null;
        }

        return theFile;
    }

    @Action
    public void saveAllFiles() {
        WordMLEditor wmlEditor = WordMLEditor.getInstance(WordMLEditor.class);
        for (JInternalFrame iframe : wmlEditor.getAllInternalFrames()) {
            if (wmlEditor.getToolbarStates().isDocumentDirty(iframe)
                    && save(iframe, null, SAVE_ALL_FILES_ACTION_NAME)) {
                wmlEditor.getToolbarStates().setDocumentDirty(iframe, false);
                wmlEditor.getToolbarStates().setLocalEditsEnabled(iframe, false);
            }
        }
    }

    @Action
    public void printPreview() {
        WordMLEditor wmlEditor = WordMLEditor.getInstance(WordMLEditor.class);
        JEditorPane editor = wmlEditor.getCurrentEditor();

        WordMLEditorKit kit = (WordMLEditorKit) editor.getEditorKit();
        kit.saveCaretText();

        Document doc = editor.getDocument();
        String filePath = (String) doc.getProperty(WordMLDocument.FILE_PATH_PROPERTY);
        DocumentElement elem = (DocumentElement) doc.getDefaultRootElement();
        DocumentML rootML = (DocumentML) elem.getElementML();

        //Do not include the last paragraph when saving or printing.
        //we'll put it back when the job is done.
        elem = (DocumentElement) elem.getElement(elem.getElementCount() - 1);
        ElementML paraML = elem.getElementML();
        ElementML bodyML = paraML.getParent();
        paraML.delete();

        try {
            WordprocessingMLPackage wordMLPackage = rootML.getWordprocessingMLPackage();

            //         XmlPackage worker = new XmlPackage(wordMLPackage);         
            //         org.docx4j.xmlPackage.Package result = worker.get();         
            //         boolean suppressDeclaration = true;
            //         boolean prettyprint = true;         
            //         System.out.println( 
            //               org.docx4j.XmlUtils.
            //                  marshaltoString(result, suppressDeclaration, prettyprint, 
            //                        org.docx4j.jaxb.Context.jcXmlPackage) );

            //Create temporary .pdf file.
            //Remember that filePath is in Commons-VFS format which
            //uses '/' as separator char.
            String tmpName = filePath.substring(filePath.lastIndexOf("/"), filePath.lastIndexOf(Constants.DOT));
            File tmpFile = File.createTempFile(tmpName + ".tmp", ".pdf");
            // Delete the temporary file when program exits.
            tmpFile.deleteOnExit();

            OutputStream os = new java.io.FileOutputStream(tmpFile);

            // Could write to a ByteBuffer and avoid the temp file if:
            // 1. com.sun.pdfview.PDFViewer had an appropriate open method
            // 2. We knew how big to make the buffer
            // java.nio.ByteBuffer buf = java.nio.ByteBuffer.allocate(15000);
            // //15kb
            // OutputStream os = newOutputStream(buf);

            PdfConversion c = new org.docx4j.convert.out.pdf.viaXSLFO.Conversion(wordMLPackage);
            // can change from viaHTML to viaIText or viaXSLFO
            PdfSettings settings = new PdfSettings();
            c.output(os, settings);

            os.close();

            PDFViewer pv = new PDFViewer(true);
            // pv.openFile(buf, "some name"); // requires modified
            // com.sun.pdfview.PDFViewer
            pv.openFile(tmpFile);

        } catch (Exception exc) {
            exc.printStackTrace();
            ResourceMap rm = wmlEditor.getContext().getResourceMap(getClass());
            String title = rm.getString(PRINT_PREVIEW_ACTION_NAME + ".Action.text");
            String message = rm.getString(PRINT_PREVIEW_ACTION_NAME + ".Action.errorMessage") + "\n"
                    + VFSUtils.getFriendlyName(filePath);
            wmlEditor.showMessageDialog(title, message, JOptionPane.ERROR_MESSAGE);

        } finally {
            //Remember to put 'paraML' as last paragraph
            bodyML.addChild(paraML);
        }

    } //printPreview()

    @Action
    public void closeFile() {
        WordMLEditor wmlEditor = WordMLEditor.getInstance(WordMLEditor.class);
        wmlEditor.closeInternalFrame(wmlEditor.getCurrentInternalFrame());
    }

    @Action
    public void closeAllFiles() {
        WordMLEditor wmlEditor = WordMLEditor.getInstance(WordMLEditor.class);
        wmlEditor.closeAllInternalFrames();
    }

    @Action
    public void exit() {
        WordMLEditor editor = WordMLEditor.getInstance(WordMLEditor.class);
        editor.exit();
    }

    private VFSJFileChooser createFileChooser(ResourceMap resourceMap, String callerActionName,
            JInternalFrame iframe, String filteredFileExtension) {

        String filePath = null;
        if (EXPORT_AS_SHARED_DOC_ACTION_NAME.equals(callerActionName)) {
            Preferences prefs = Preferences.userNodeForPackage(getClass());
            filePath = prefs.get(Constants.LAST_OPENED_FILE, Constants.EMPTY_STRING);
        } else {
            filePath = (String) iframe.getClientProperty(WordMLDocument.FILE_PATH_PROPERTY);
        }

        FileObject file = null;
        FileObject dir = null;
        try {
            file = VFSUtils.getFileSystemManager().resolveFile(filePath);
            dir = file.getParent();
        } catch (FileSystemException exc) {
            ;//ignore
        }

        return createFileChooser(resourceMap, dir, filteredFileExtension);
    }

    private VFSJFileChooser createFileChooser(ResourceMap resourceMap, FileObject showedDir,
            String filteredFileExtension) {

        VFSJFileChooser chooser = new VFSJFileChooser();
        chooser.setAccessory(new DefaultAccessoriesPanel(chooser));
        chooser.setFileHidingEnabled(false);
        chooser.setMultiSelectionEnabled(false);

        chooser.setFileSelectionMode(SELECTION_MODE.FILES_ONLY);

        String desc = null;
        if (Constants.HTML_STRING.equals(filteredFileExtension)) {
            desc = resourceMap.getString(Constants.VFSJFILECHOOSER_HTML_FILTER_DESC);
            if (desc == null || desc.length() == 0) {
                desc = "Html Files (.html)";
            }
        } else {
            desc = resourceMap.getString(Constants.VFSJFILECHOOSER_DOCX_FILTER_DESC);
            if (desc == null || desc.length() == 0) {
                desc = "Docx Files (.docx, .xml)";
            }
        }

        if (showedDir == null) {
            String s = resourceMap.getString(Constants.VFSJFILECHOOSER_DEFAULT_FOLDER_URI);
            if (s != null && s.length() > 0) {
                try {
                    showedDir = VFSUtils.getFileSystemManager().resolveFile(s);
                } catch (FileSystemException exc) {
                    StringBuilder sb = new StringBuilder();
                    sb.append("Bad ");
                    sb.append(Constants.VFSJFILECHOOSER_DEFAULT_FOLDER_URI);
                    sb.append(" property.");
                    throw new RuntimeException(sb.toString());
                }
            } else {
                showedDir = null;
            }
        }

        FileNameExtensionFilter filter;
        if (Constants.DOCX_STRING.equals(filteredFileExtension)) {
            // Add .xml as well
            filter = new FileNameExtensionFilter(desc, filteredFileExtension, Constants.FLAT_OPC_STRING);
        } else {
            filter = new FileNameExtensionFilter(desc, filteredFileExtension);
        }
        chooser.addChoosableFileFilter(filter);
        chooser.setCurrentDirectory(showedDir);

        return chooser;
    }

    public void createInFileSystem(FileObject file) throws FileSystemException {
        FileObject parent = file.getParent();
        String uri = UriParser.decode(parent.getName().getURI());

        if (System.getProperty("os.name").toUpperCase().indexOf("WINDOWS") > -1
                && parent.getName().getScheme().startsWith("file") && !parent.isWriteable()
                && (uri.indexOf("/Documents") > -1 || uri.indexOf("/My Documents") > -1)) {
            //TODO: Check whether we still need this workaround.
            //See http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4939819
            //Re: File.canWrite() returns false for the "My Documents" directory (win)
            String localpath = org.docx4j.utils.VFSUtils.getLocalFilePath(parent);
            File f = new File(localpath);
            f.setWritable(true, true);
        }

        file.createFile();
    }

    /**
     * Saves editor documents to a file.
     * 
     * Internal frame may have two editors for presenting two different views
     * to user namely editor view and source view. WordMLTextPane is used for 
     * editor view and JEditorPane for source view.
     * The contents of these two editors are synchronized when user switches
     * from one view to the other. Therefore, there will be ONLY ONE editor 
     * that is dirty and has to be saved by this method.
     * 
     * @param iframe
     * @param saveAsFilePath
     * @param callerActionName
     * @return
     */
    public boolean save(JInternalFrame iframe, String saveAsFilePath, String callerActionName) {
        boolean success = true;

        if (saveAsFilePath == null) {
            saveAsFilePath = (String) iframe.getClientProperty(WordMLDocument.FILE_PATH_PROPERTY);
        }

        if (log.isDebugEnabled()) {
            log.debug("save(): filePath=" + VFSUtils.getFriendlyName(saveAsFilePath));
        }

        WordMLTextPane editorView = SwingUtil.getWordMLTextPane(iframe);
        JEditorPane sourceView = SwingUtil.getSourceEditor(iframe);

        if (sourceView != null && !((Boolean) sourceView.getClientProperty(Constants.LOCAL_VIEWS_SYNCHRONIZED_FLAG))
                .booleanValue()) {
            //signifies that Source View is not synchronised with Editor View yet.
            //Therefore, it is dirty and has to be saved.
            if (editorView != null && editorView.getWordMLEditorKit().getPlutextClient() != null) {
                //Document has to be saved from editor view 
                //by committing local edits
                success = false;
            } else {
                EditorKit kit = sourceView.getEditorKit();
                Document doc = sourceView.getDocument();
                WordprocessingMLPackage wmlPackage = (WordprocessingMLPackage) doc
                        .getProperty(WordMLDocument.WML_PACKAGE_PROPERTY);

                DocUtil.write(kit, doc, wmlPackage);
                success = save(wmlPackage, saveAsFilePath, callerActionName);

                if (success) {
                    if (saveAsFilePath.endsWith(Constants.DOCX_STRING)
                            || saveAsFilePath.endsWith(Constants.FLAT_OPC_STRING)) {
                        doc.putProperty(WordMLDocument.FILE_PATH_PROPERTY, saveAsFilePath);
                        iframe.putClientProperty(WordMLDocument.FILE_PATH_PROPERTY, saveAsFilePath);
                    }
                }
            }
            return success;
        }
        sourceView = null;

        if (editorView == null) {
            ;//pass

        } else if (editorView.getWordMLEditorKit().getPlutextClient() != null) {
            if (saveAsFilePath.equals(editorView.getDocument().getProperty(WordMLDocument.FILE_PATH_PROPERTY))) {
                success = commitLocalChanges(editorView, callerActionName);

            } else {
                //TODO: Enable saving Plutext document as a new file.
                WordMLEditor wmlEditor = WordMLEditor.getInstance(WordMLEditor.class);
                ResourceMap rm = wmlEditor.getContext().getResourceMap(getClass());
                String title = rm.getString(callerActionName + ".Action.text");
                StringBuilder message = new StringBuilder();
                message.append("File ");
                message.append(saveAsFilePath);
                message.append(Constants.NEWLINE);
                message.append(rm.getString(callerActionName + ".Action.wrong.fileName.infoMessage"));
                wmlEditor.showMessageDialog(title, message.toString(), JOptionPane.INFORMATION_MESSAGE);

                success = false;
            }
        } else {
            WordMLEditorKit kit = (WordMLEditorKit) editorView.getEditorKit();
            kit.saveCaretText();

            Document doc = editorView.getDocument();
            DocumentElement elem = (DocumentElement) doc.getDefaultRootElement();
            DocumentML rootML = (DocumentML) elem.getElementML();

            //Do not include the last paragraph when saving.
            //After saving we put it back.
            elem = (DocumentElement) elem.getElement(elem.getElementCount() - 1);
            ElementML paraML = elem.getElementML();
            ElementML bodyML = paraML.getParent();
            paraML.delete();

            success = save(rootML.getWordprocessingMLPackage(), saveAsFilePath, callerActionName);

            //Remember to put 'paraML' as last paragraph
            bodyML.addChild(paraML);

            if (success) {
                if (saveAsFilePath.endsWith(Constants.DOCX_STRING)) {
                    doc.putProperty(WordMLDocument.FILE_PATH_PROPERTY, saveAsFilePath);
                    iframe.putClientProperty(WordMLDocument.FILE_PATH_PROPERTY, saveAsFilePath);
                }
            }
        }

        return success;
    }

    private boolean commitLocalChanges(WordMLTextPane editor, String callerActionName) {
        return PlutextMenu.getInstance().commitLocalEdits(editor, callerActionName);
    }

    protected boolean save(WordprocessingMLPackage wmlPackage, String saveAsFilePath, String callerActionName) {
        boolean success = true;
        try {
            if (saveAsFilePath.endsWith(Constants.DOCX_STRING)) {
                SaveToVFSZipFile saver = new SaveToVFSZipFile(wmlPackage);
                saver.save(saveAsFilePath);
            } else if (saveAsFilePath.endsWith(Constants.FLAT_OPC_STRING)) {

                FlatOpcXmlCreator xmlPackageCreator = new FlatOpcXmlCreator(wmlPackage);
                org.docx4j.xmlPackage.Package flatOPC = xmlPackageCreator.get();

                FileObject fo = VFSUtils.getFileSystemManager().resolveFile(saveAsFilePath);
                OutputStream fos = fo.getContent().getOutputStream();

                Marshaller m = Context.jcXmlPackage.createMarshaller();
                try {
                    NamespacePrefixMapperUtils.setProperty(m, NamespacePrefixMapperUtils.getPrefixMapper());

                    m.setProperty("jaxb.formatted.output", true);
                } catch (javax.xml.bind.PropertyException cnfe) {
                    log.error(cnfe.getMessage(), cnfe);
                }
                m.marshal(flatOPC, fos);
                try {
                    //just in case
                    fos.close();
                } catch (IOException exc) {
                    ;//ignore
                }

            } else if (saveAsFilePath.endsWith(Constants.HTML_STRING)) {
                FileObject fo = VFSUtils.getFileSystemManager().resolveFile(saveAsFilePath);
                OutputStream fos = fo.getContent().getOutputStream();
                javax.xml.transform.stream.StreamResult result = new javax.xml.transform.stream.StreamResult(fos);
                //wmlPackage.html(result);
                AbstractHtmlExporter exporter = new HtmlExporterNG2();

                // .. the HtmlSettings object
                HtmlSettings htmlSettings = new HtmlSettings();
                htmlSettings.setImageDirPath(saveAsFilePath + "_files");
                htmlSettings.setImageTargetUri(
                        saveAsFilePath.substring(saveAsFilePath.lastIndexOf("/") + 1) + "_files");

                exporter.html(wmlPackage, result, htmlSettings);

                try {
                    //just in case
                    fos.close();
                } catch (IOException exc) {
                    ;//ignore
                }
            } else {
                throw new Docx4JException("Invalid filepath = " + VFSUtils.getFriendlyName(saveAsFilePath));
            }
        } catch (Exception exc) {
            exc.printStackTrace();

            success = false;
            WordMLEditor wmlEditor = WordMLEditor.getInstance(WordMLEditor.class);
            ResourceMap rm = wmlEditor.getContext().getResourceMap(getClass());

            String title = rm.getString(callerActionName + ".Action.text");
            String message = rm.getString(callerActionName + ".Action.errorMessage") + "\n"
                    + VFSUtils.getFriendlyName(saveAsFilePath);
            wmlEditor.showMessageDialog(title, message, JOptionPane.ERROR_MESSAGE);
        }

        return success;
    }

    public boolean export(JInternalFrame iframe, String saveAsFilePath, String callerActionName) {
        log.debug("export(): filePath=" + VFSUtils.getFriendlyName(saveAsFilePath));

        WordprocessingMLPackage srcPackage = null;

        WordMLTextPane editorView = SwingUtil.getWordMLTextPane(iframe);
        JEditorPane sourceView = SwingUtil.getSourceEditor(iframe);

        if (sourceView != null && !((Boolean) sourceView.getClientProperty(Constants.LOCAL_VIEWS_SYNCHRONIZED_FLAG))
                .booleanValue()) {
            //signifies that Source View is not synchronised with Editor View yet.
            //Therefore, export from Source View.
            EditorKit kit = sourceView.getEditorKit();
            Document doc = sourceView.getDocument();
            srcPackage = DocUtil.write(kit, doc, null);
            editorView = null;
        }
        sourceView = null;

        if (editorView == null) {
            ;//pass
        } else {
            WordMLDocument doc = (WordMLDocument) editorView.getDocument();
            DocumentElement root = (DocumentElement) doc.getDefaultRootElement();
            DocumentML docML = (DocumentML) root.getElementML();
            srcPackage = docML.getWordprocessingMLPackage();
        }

        boolean success = save(XmlUtil.export(srcPackage), saveAsFilePath, callerActionName);

        log.debug("export(): success=" + success + " filePath=" + VFSUtils.getFriendlyName(saveAsFilePath));

        return success;
    }

}// FileMenu class