/*
 * This code is part of Project Waterloo from King's College London
 * 
 *
 * Copyright King's College London 2012-
 *
 * @author Malcolm Lidierth, King's College London  [Contact]
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program.  If not, see .
 *
 */
package kcl.waterloo.actions;

import java.awt.AWTPermission;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.FileDialog;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.datatransfer.Clipboard;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import javax.imageio.ImageIO;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.filechooser.FileFilter;
import javax.swing.filechooser.FileNameExtensionFilter;
import kcl.waterloo.defaults.GJDefaults;
import kcl.waterloo.deploy.image.ImageSupport;
import kcl.waterloo.deploy.pde.PDEGraphics2D;
import kcl.waterloo.export.ExportFactory;
import kcl.waterloo.graphics.GJBasicPanel;
import kcl.waterloo.graphics.GJBasicPanel.LocalTransferable;
import kcl.waterloo.graphics.GJGraphInterface;
import kcl.waterloo.gui.file.FileUtil;
import kcl.waterloo.gui.file.ImageFileChooser;
import kcl.waterloo.logging.CommonLogger;
import kcl.waterloo.swing.GCFrame;
import kcl.waterloo.swing.GCGridContainer;
import kcl.waterloo.xml.FileWrapper;
import kcl.waterloo.xml.GJDecoder;
import kcl.waterloo.xml.GJEncoder;

/**
 * This class provides static methods for commmon menu and button actions used
 * in various Waterloo project packages. These methods are intended primarily
 * for use within Waterloo code - but may also be useful in user-developed
 * menus/GUIs.
 *
 * @author Malcolm Lidierth, King's College London  [Contact]
 */
public class ActionServices {

    private static class Singleton {

        // Not used, but causes exportFactoryPresent to be set
        private final static ActionServices instance = new ActionServices();
        private static boolean exportFactoryPresent;
        private static boolean useChooser = true;
        private static CommonLogger logger;

    }

    /**
     * Non-instantiable class - static library.
     */
    private ActionServices() {
        try {
            Class c = Class.forName("kcl.waterloo.export.ExportFactory");
            if (c != null) {
                Singleton.exportFactoryPresent = true;
            }
        } catch (ClassNotFoundException ex) {
            Singleton.exportFactoryPresent = false;
        }
        Singleton.logger = new CommonLogger(ActionServices.class.getName());
    }

    /**
     * @return the useChooser flag
     */
    public static boolean isUseChooser() {
        return Singleton.useChooser;
    }

    /**
     * @param aUseChooser if true, file dialogs will use the cross-platform
     * JFileChooser. If false, a FileDialog will be used.
     */
    public static void setUseChooser(boolean aUseChooser) {
        Singleton.useChooser = aUseChooser;
    }

    public static FileWrapper open() {
        return open(null);
    }

    /**
     * Displays a file open dialog, loads the selected Waterloo graphics XML
     * file and returns the details in a FileWrapper instance.
     *
     * If the file contains multiple objects, the contents will be an ArrayList
     * of objects.
     *
     * @param parent the component whose parent Frame (if any) will be used
     * @return the de-serialized file contents
     */
    @SuppressWarnings(value = "unchecked")
    public static FileWrapper open(Component parent) {
        File file;
        if (isUseChooser()) {
            JFileChooser chooser = new JFileChooser();
            chooser.addChoosableFileFilter(new FileNameExtensionFilter("Waterloo graphics (.kclf)", "kclf"));
            chooser.addChoosableFileFilter(new FileNameExtensionFilter("Compressed Waterloo graphics (.kclf.gz)", "gz"));
            chooser.addChoosableFileFilter(new FileNameExtensionFilter("Waterloo MATLAB folders (.kclfig)", "kclfig"));
            chooser.addChoosableFileFilter(new FileNameExtensionFilter("All Waterloo Files", new String[]{"kclf", "gz", "kclfig"}));
            int val = chooser.showOpenDialog(parent);
            if (val != JFileChooser.APPROVE_OPTION) {
                return new FileWrapper(null, null);
            }
            file = chooser.getSelectedFile();
        } else {
            parent = (parent != null) ? SwingUtilities.windowForComponent(parent) : null;
            Frame parent2 = (parent instanceof Frame) ? (Frame) SwingUtilities.windowForComponent(parent) : null;
            FileDialog chooser = new FileDialog(parent2, "Open File", FileDialog.LOAD);
            chooser.setLocationByPlatform(true);
            chooser.setFilenameFilter(new WaterlooFileOpenFilter());
            chooser.setVisible(true);
            file = new File(chooser.getDirectory(), chooser.getFile());
        }

        Singleton.logger.debug(String.format("Loading: %s", file.getPath()));

        FileWrapper fileWrapper;
        if (file.isDirectory() && file.getName().endsWith(".kclfig")) {
            fileWrapper = getKCLFFile(file);
        } else {
            fileWrapper = new FileWrapper(file, null);
        }

        Object loadedObject;

        String s = fileWrapper.getFile().toString();
        loadedObject = GJDecoder.load(s);

        if (loadedObject instanceof LinkedHashMap) {
            LinkedHashMap map = (LinkedHashMap) loadedObject;
            Object newObj = map.get("Graphics");
            fileWrapper.setContents(newObj);
            fileWrapper.setErrorLog((ArrayList) map.get("ErrorLog"));
            Singleton.logger.debug(String.format("Loaded: %s", file.getPath()));
            return fileWrapper;
        } else {
            Singleton.logger.debug(String.format("Loaded: %s", file.getPath()));
            return new FileWrapper(null, null);
        }

    }

    public static FileWrapper save(Object o) {
        return save(null, o);
    }

    /**
     * Displays a file chooser and saves the specified Object to file by calling
     * the GJEncoder save method.
     *
     * @param parent
     * @param o Object recognizable by GJDecoder
     * @return a FileWrapper
     */
    public static FileWrapper save(Component parent, Object o) {
        File file;
        if (isUseChooser()) {
            JFileChooser chooser = new JFileChooser();
            int val = chooser.showSaveDialog(parent);
            if (val != JFileChooser.APPROVE_OPTION) {
                return new FileWrapper(null, null);
            }
            file = chooser.getSelectedFile();
        } else {
            parent = (parent != null) ? SwingUtilities.windowForComponent(parent) : null;
            Frame parent2 = (parent instanceof Frame) ? (Frame) SwingUtilities.windowForComponent(parent) : null;
            FileDialog chooser = new FileDialog(parent2, "Save File", FileDialog.SAVE);
            chooser.setFilenameFilter(new WaterlooFileSaveFilter());
            chooser.setLocationByPlatform(true);
            chooser.setVisible(true);
            file = new File(chooser.getDirectory(), chooser.getFile());
        }

        Singleton.logger.debug(String.format("Saving: %s", file.getPath()));
        GJEncoder.save(file.getPath(), o);
        Singleton.logger.debug(String.format("Saved: %s", file.getPath()));
        return new FileWrapper(null, null);
    }

    public static void deployAs(Component c2) {
        deployAs(null, c2);
    }

    public static void deployAs(Component parent, final Component c2) {
        String folder;
        File file;
        if (isUseChooser()) {
            JFileChooser chooser = new JFileChooser();
            chooser.addChoosableFileFilter(new FileNameExtensionFilter("ProcessingJS (.pde)", "pde"));
            chooser.addChoosableFileFilter(new FileNameExtensionFilter("Scalable Vector Graphics (.svg)", "svg"));
            int val = chooser.showSaveDialog(parent);
            if (val != JFileChooser.APPROVE_OPTION) {
                return;
            }
            file = chooser.getSelectedFile();
            folder = chooser.getCurrentDirectory().getPath();
        } else {
            parent = (parent != null) ? SwingUtilities.windowForComponent(parent) : null;
            Frame parent2 = (parent instanceof Frame) ? (Frame) SwingUtilities.windowForComponent(parent) : null;
            FileDialog chooser = new FileDialog(parent2, "Deploy to Web", FileDialog.SAVE);
            chooser.setFilenameFilter(new WaterlooDeployFilter());
            chooser.setLocationByPlatform(true);
            chooser.setVisible(true);
            file = new File(chooser.getDirectory(), chooser.getFile());
            folder = chooser.getDirectory();
        }
        String filename = file.getName();
        if (!filename.endsWith(".svg") && !filename.endsWith(".pde")) {
            // Default to setting in defaults table
            filename = filename.concat(".").concat((String) GJDefaults.getMap2().get("DeployMode"));
        }

        final String ext = getExtension(filename);
        final File file2 = new File(folder, filename);
        final String folder2 = file2.getPath().replace(".".concat(getExtension(file2.getPath())), "");

        if (ext.equals("pde")) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    PDEGraphics2D g2 = PDEGraphics2D.paint(c2);
                    String jsLoc = (String) GJDefaults.getMap().get("Processing.jsLocation");
                    String cssLoc = (String) GJDefaults.getMap().get("Processing.cssLocation");
                    boolean httpd = ((Boolean) GJDefaults.getMap().get("Processing.httpd"));
                    try {
                        g2.write(file2.getPath(), true, jsLoc, cssLoc, httpd);
                        Singleton.logger.debug(String.format("PDE file saved to folder: %s", folder2));
                    } catch (IOException ex) {
                        Singleton.logger.warn("IOException: " + ex.getMessage());
                    } finally {

                    }
                }
            });
        } else if (Singleton.exportFactoryPresent) {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        ExportFactory.deploySVG(c2, file2,
                                c2.getSize(),
                                false,
                                ((String) GJDefaults.getMap().get("SVG.cssLocation")),
                                ((Boolean) GJDefaults.getMap().get("SVG.httpd")).booleanValue(),
                                new ArrayList(),
                                "",
                                "");
                        Singleton.logger.debug(String.format("SVG file saved to folder: %s", folder2));
                    } catch (IOException ex) {
                        Singleton.logger.warn("IOException: " + ex.getMessage());
                    } finally {

                    }
                }
            });
        }

    }

    public static void saveAs(Component c) {
        saveAs(null, c);
    }

    /**
     * Displays a file save dialog and saves a Component in the selected format.
     *
     * @param parent
     * @param c an AWT component
     */
    public static void saveAs(Component parent, Component c) {
        if ((c instanceof GJGraphInterface) && ((GJGraphInterface) c).getGraphContainer() != null) {
            c = ((GJGraphInterface) c).getGraphContainer();
        }
        boolean opaqueFlag = c.isOpaque();
        if (c instanceof JComponent) {
            ((JComponent) c).setOpaque(true);
        }
        File file = null;
        try {
            if (isUseChooser()) {
                int val = ImageFileChooser.createSaveDialog(parent, "");
                switch (val) {
                    case javax.swing.JFileChooser.APPROVE_OPTION:
                        return;
                }
                ImageFileChooser fc = ImageFileChooser.getInstance();
                file = fc.getSelectedFile();
            } else {
                parent = (parent != null) ? SwingUtilities.windowForComponent(parent) : null;
                Frame parent2 = (parent instanceof Frame) ? (Frame) SwingUtilities.windowForComponent(parent) : null;
                FileDialog chooser = new FileDialog(parent2, "Deploy to Web", FileDialog.SAVE);
                chooser.setLocationByPlatform(true);
                chooser.setVisible(true);
                file = new File(chooser.getDirectory(), chooser.getFile());
            }
            c = getCopyOrSaveTarget(c);
            String ext = FileUtil.getExtension(file);
            Singleton.logger.debug(String.format("Saving: %s", file.getPath()));
            if (Singleton.exportFactoryPresent && ext.equals("pdf")) {
                ExportFactory.saveAsPDF(c, file);
            } else if (ext.equals("eps")) {
                ExportFactory.saveAsEPS(c, file);
            } else if (Singleton.exportFactoryPresent && ext.equals("svg")) {
                ExportFactory.saveAsSVG(c, file);
            } else if (Singleton.exportFactoryPresent && ext.equals("gz")) {
                ExportFactory.saveAsCompressedSVG(c, file);
            } else if (ext.equals("pde")) {
                PDEGraphics2D g2 = new PDEGraphics2D((Graphics2D) c.getGraphics(), c.getSize());
                c.paint(g2);
                g2.write(file.getPath(), false, "");
            } else {
                BufferedImage buffer = c.getGraphicsConfiguration().createCompatibleImage(c.getWidth(), c.getHeight());
                Graphics2D g2 = (Graphics2D) buffer.getGraphics();
                c.paint(g2);
                if (ext.isEmpty()) {
                    ext = "png";
                    file = new File(file.getPath().concat(".png"));
                }
                ImageIO.write(buffer, ext, file);
            }
            Singleton.logger.debug(String.format("Saved: %s", file.getPath()));
        } catch (IOException ex) {
            if (file != null) {
                Singleton.logger.warn(String.format("IOException saving file: %s", file.getPath()));
            } else {
                Singleton.logger.warn(String.format("IOException saving file"));
            }
        } finally {
            if (c instanceof JComponent) {
                ((JComponent) c).setOpaque(opaqueFlag);
            }
        }
    }

    /**
     * Copies the graphics of a GJBasicPanel or subclass to the clipboard.
     *
     * @param panel a GJBasicPanel
     */
    public static void copy(GJBasicPanel panel) {
        Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
        LocalTransferable t = panel.getTransferable();
        clipboard.setContents(t, t);
    }

    /**
     * Copies the graphics of a GJBasicPanel or subclass to the clipboard in the
     * background. Returns the associated SwingWorker.
     *
     * @param panel a GJBasicPanel
     * @return the SwingWorker for the task
     */
    public static SwingWorker copyGraphics(final GJBasicPanel panel) {
        SwingWorker worker = new SwingWorker() {
            @Override
            protected Boolean doInBackground() throws Exception {
                try {
                    SecurityManager manager = System.getSecurityManager();
                    if (manager != null) {
                        manager.checkPermission(new AWTPermission("accessClipboard"));
                        //manager.checkSystemClipboardAccess();
                    }
                    Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
                    GJBasicPanel panel2 = (GJBasicPanel) getCopyOrSaveTarget(panel);
                    LocalTransferable t = panel2.getTransferable();
                    try {
                        clipboard.setContents(t, t);
                    } catch (Exception ex) {
                        // Some versions of Java 7/8 will throw an IOException here.
                        // Java Bug - see https://bugs.openjdk.java.net/browse/JDK-7124253
                        Singleton.logger.warn(ex.getMessage());
                    }
                    return Boolean.TRUE;
                } catch (SecurityException ex) {
                    Singleton.logger.warn("SecurityException: Clipboard access is not available");
                }
                return Boolean.FALSE;
            }
        };
        worker.execute();
        return worker;
    }

    /**
     * Copies the graphics of a GJBasicPanel or subclass to the clipboard in
     * bitmap format only.
     *
     * @param panel a GJBasicPanel
     */
    public static void copyAsImage(GJBasicPanel panel) {
        try {
            SecurityManager manager = System.getSecurityManager();
            if (manager != null) {
                manager.checkPermission(new AWTPermission("accessClipboard"));
            }
            Clipboard clipboard = Toolkit.getDefaultToolkit().getSystemClipboard();
            panel = (GJBasicPanel) getCopyOrSaveTarget(panel);
            LocalTransferable t = panel.getTransferable(false);
            clipboard.setContents(t, t);
        } catch (SecurityException ex) {
            Singleton.logger.warn("SecurityException: Clipboard access is not available");
        }
    }

    public static Component getCopyOrSaveTarget(Component c) {
        if (c instanceof GCFrame) {
            c = (Container) ((GCFrame) c).getGraphicsContainer();
        } else if (c instanceof GCGridContainer) {
            c = ((GCGridContainer) c).getGrid();
        } else if (c instanceof GJGraphInterface
                && ((GJGraphInterface) c).getGraphContainer() != null) {
            c = ((GJGraphInterface) c).getGraphContainer();
        }
        return c;
    }

    public static void editDefaults() {
        GJDefaults.editDefaults();
    }

    private static FileWrapper getKCLFFile(File file) {
        File[] f = file.listFiles();
        File graphicsFile = null;
        ArrayList imageFiles = new ArrayList();
        for (File f1 : f) {
            if (graphicsFile == null && f1.getName().endsWith(".kclf") || f1.getName().endsWith(".kclf.gz")) {
                graphicsFile = f1;
            }
            if (ImageSupport.isImageFormatSupported(f1)) {
                imageFiles.add(f1);
            }
        }
        return new FileWrapper(graphicsFile, null, imageFiles);
    }

    /**
     * @return the Singleton.exportFactoryPresent
     */
    public static boolean isExportFactoryPresent() {
        return Singleton.exportFactoryPresent;
    }

    public static String getExtension(String s) {
        if (s.contains(".")) {
            int idx = s.lastIndexOf(".");
            return s.substring(idx + 1);
        } else {
            return "";

        }
    }

    private static class WaterlooFileOpenFilter implements FilenameFilter {

        private WaterlooFileOpenFilter() {
        }

        @Override
        public boolean accept(File f, String s) {
            String extension = getExtension(s);
            if (extension != null) {
                return extension.equals("kclf") || extension.equals("gz") || extension.equals("kclfig");
            } else {
                return false;
            }
        }

    }

    private static class JWaterlooFileOpenFilter extends FileFilter {

        @Override
        public boolean accept(File s) {
            String extension = FileUtil.getExtension(s);
            if (extension != null) {
                return extension.equals("kclf") || extension.equals("gz") || extension.equals("kclfig");
            } else {
                return false;
            }
        }

        @Override
        public String getDescription() {
            return "All Waterloo Files";
        }

    }

    private static class WaterlooDeployFilter implements FilenameFilter {

        private WaterlooDeployFilter() {
        }

        @Override
        public boolean accept(File f, String s) {
            String extension = getExtension(s);
            if (extension != null) {
                return extension.equals("pde") || extension.equals("svg");
            } else {
                return false;
            }
        }

    }

    private static class WaterlooFileSaveFilter implements FilenameFilter {

        private WaterlooFileSaveFilter() {
        }

        @Override
        public boolean accept(File f, String s) {
            String extension = getExtension(s);
            if (extension != null) {
                return extension.equals("kclf") || extension.equals("gz");
            } else {
                return false;
            }
        }

    }
}

 

Ads help maintain this website.