com.nokia.tools.screen.ui.utils.FileChangeWatchThread.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.tools.screen.ui.utils.FileChangeWatchThread.java

Source

/*
* Copyright (c) 2006-2010 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
package com.nokia.tools.screen.ui.utils;

import java.awt.image.RenderedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.HashSet;
import java.util.Set;

import javax.imageio.ImageIO;

import org.apache.batik.dom.svg.SVGDOMImplementation;
import org.apache.batik.dom.util.DOMUtilities;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.nokia.tools.media.image.CoreImage;
import com.nokia.tools.media.utils.IFileConstants;
import com.nokia.tools.media.utils.IMediaConstants;
import com.nokia.tools.media.utils.RunnableWithParameter;
import com.nokia.tools.media.utils.UtilsPlugin;
import com.nokia.tools.media.utils.svg.SvgUtil;
import com.nokia.tools.resource.util.DebugHelper;
import com.nokia.tools.resource.util.FileUtils;
import com.nokia.tools.resource.util.XmlUtil;
import com.nokia.tools.screen.ui.branding.IBrandingManager;
import com.nokia.tools.screen.ui.editor.Messages;
import com.nokia.tools.ui.branding.extension.BrandingExtensionManager;

/**
 * when 3rd party image editing tool is launched, this thread watch file status
 * and updates selected layer if file is changed. 
 */
public class FileChangeWatchThread extends Thread {

    private static final long CHECK_INTERVAL = 1000; // in millis

    public static final FileChangeWatchThread INSTANCE;

    static {
        INSTANCE = new FileChangeWatchThread();
        INSTANCE.start();
    }

    public static class FileInfo {
        File file;

        long initialDate, initialSize;

        Runnable callback;

        boolean canUpdate;

        private boolean callbackInUIThread;

        FileInfo(File file, Runnable callback) {
            this(file, callback, true, callback != null);
        }

        FileInfo(File file, Runnable callback, boolean canUpdate, boolean callbackInUIThread) {
            this.file = file.getAbsoluteFile();
            this.initialDate = file.lastModified();
            this.initialSize = file.length();
            this.callback = callback;
            this.canUpdate = canUpdate;
            this.callbackInUIThread = callbackInUIThread;

            FileUtils.addForCleanup(this.file);
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof FileInfo) {
                return file.equals(((FileInfo) obj).file);
            } else {
                return super.equals(obj);
            }
        }

        @Override
        public int hashCode() {
            return file.hashCode();
        }

        public boolean isCanUpdate() {
            return canUpdate;
        }

        public void setCanUpdate(boolean canUpdate) {
            this.canUpdate = canUpdate;
        }
    }

    // file we are watching
    private Set<FileInfo> watchedFiles = new HashSet<FileInfo>();

    private FileChangeWatchThread() {
        try {
            setDaemon(true);
            setName(FileChangeWatchThread.class.getSimpleName());
            setPriority(Thread.MIN_PRIORITY);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public FileInfo addWatchedFile(File file, Runnable callback) {
        FileInfo info = new FileInfo(file, callback);
        synchronized (watchedFiles) {
            watchedFiles.add(info);
            if (DebugHelper.debugCleanResource()) {
                DebugHelper.debug(this,
                        "Added: " + file + ", callback: " + callback + ", watch size: " + watchedFiles.size());
            }
        }

        synchronized (this) {
            notify();
        }

        return info;
    }

    public FileInfo addWatchedFile(File file, Runnable callback, boolean canUpdate, boolean callbackInUIThread) {
        FileInfo info = new FileInfo(file, callback, canUpdate, callbackInUIThread);
        synchronized (watchedFiles) {
            watchedFiles.add(info);
            if (DebugHelper.debugCleanResource()) {
                DebugHelper.debug(this,
                        "Added: " + file + ", callback: " + callback + ", watch size: " + watchedFiles.size());
            }
        }

        synchronized (this) {
            notify();
        }

        return info;
    }

    @Override
    public void run() {
        int counter = 0;
        while (true) {
            try {
                try {
                    Thread.sleep(CHECK_INTERVAL);
                } catch (InterruptedException e) {
                }
                counter++;
                Set<FileInfo> files = null;
                synchronized (watchedFiles) {
                    files = new HashSet<FileInfo>(watchedFiles);
                }

                for (FileInfo info : files) {
                    if (info.canUpdate) {
                        if (info.initialDate != info.file.lastModified()
                                || info.initialSize != info.file.length()) {
                            // file modified
                            try {

                                if (info.initialDate != info.file.lastModified()
                                        || info.initialSize != info.file.length()) {

                                    if (info.callback instanceof RunnableWithParameter) {
                                        ((RunnableWithParameter) info.callback)
                                                .setParameter(info.file.getAbsolutePath());
                                    }

                                    if (info.callback != null) {
                                        try {

                                            if (info.callbackInUIThread) {
                                                if (Display.getCurrent() == null) {
                                                    Display.getDefault().asyncExec(info.callback);
                                                }
                                            } else
                                                info.callback.run();
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                    }
                                    info.initialDate = info.file.lastModified();
                                    info.initialSize = info.file.length();
                                }
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        }
                    } else {
                        watchedFiles.remove(info);
                        if (DebugHelper.debugCleanResource()) {
                            DebugHelper.debug(this, "Removed: " + info.file + ", callback: " + info.callback
                                    + ", watch size: " + watchedFiles.size());
                        }
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private static File getWorkDir(String editorPath) {
        return new File(editorPath).getParentFile();
    }

    /**
     * opens 3rd party program and edit given file. Convenience method, should
     * not be here, move later.
     * 
     * @param editorPath
     * @param im
     * @param layer
     * @param callback
     *            when image succesfully updated, callback is executed
     * @param runCallBackInUIThread
     * @throws IOException
     */
    public static FileInfo open3rdPartyEditor(String editorPath, RenderedImage im, String imagePrefix,
            RunnableWithParameter callback, boolean runCallBackInUIThread) throws IOException {
        return open3rdPartyEditor(editorPath, im, imagePrefix, callback, runCallBackInUIThread, null, false);
    }

    /**
     * opens 3rd party program and edit given file. Convenience method, should
     * not be here, move later.
     * 
     * @param editorPath
     * @param im
     * @param layer
     * @param callback
     *            when image succesfully updated, callback is executed
     * @param runCallBackInUIThread
     * @throws IOException
     */
    public static FileInfo open3rdPartyEditor(String editorPath, RenderedImage im, String imagePrefix,
            RunnableWithParameter callback, boolean runCallBackInUIThread, String format, boolean removeAplha)
            throws IOException {

        if (format == null)
            format = "png";

        if (IMediaConstants.PREF_BITMAP_EDITOR.equals(editorPath)) {
            editorPath = getEditorPath(IMediaConstants.PREF_BITMAP_EDITOR);
        } else if (IMediaConstants.PREF_VECTOR_EDITOR.equals(editorPath)) {
            editorPath = getEditorPath(IMediaConstants.PREF_VECTOR_EDITOR);
        } else if (IMediaConstants.PREF_SOUND_EDITOR.equals(editorPath)) {
            editorPath = getEditorPath(IMediaConstants.PREF_SOUND_EDITOR);
        } else if (editorPath == null) {
            editorPath = getEditorPath(IMediaConstants.PREF_BITMAP_EDITOR);
        }

        if (editorPath == null || editorPath.trim().length() == 0) {
            throw new IllegalArgumentException("Editor not defined.");
        }

        if (removeAplha) {
            // remove alpha channel
            im = CoreImage.create(im).removeAlpha().getAwt();
        }

        // create a temp file
        File imFile = new File(
                FileUtils.generateUniqueFileName(imagePrefix == null ? "image" : imagePrefix, format));
        ImageIO.write(im, format, imFile);

        Runtime.getRuntime().exec(editorPath + " " + imFile.getAbsolutePath());

        // add file to watcher thread
        return INSTANCE.addWatchedFile(imFile, callback, true, runCallBackInUIThread);
    }

    /**
     * opens 3rd party program and edit given file. Convenience method, should
     * not be here, move later.
     * 
     * @param program
     * @param im
     * @param layer
     * @param callback
     *            when image succesfully updated, callback is executed
     * @param runCallBackInUIThread
     * @throws IOException
     */
    public static FileInfo open3rdPartyProgram(Program program, RenderedImage im, String imagePrefix,
            RunnableWithParameter callback, boolean runCallBackInUIThread) throws IOException {
        return open3rdPartyProgram(program, im, imagePrefix, callback, runCallBackInUIThread, null, false);
    }

    /**
     * opens 3rd party program and edit given file. Convenience method, should
     * not be here, move later.
     * 
     * @param editorPath
     * @param im
     * @param layer
     * @param callback
     *            when image succesfully updated, callback is executed
     * @param runCallBackInUIThread
     * @throws IOException
     */
    public static FileInfo open3rdPartyProgram(Program program, RenderedImage im, String imagePrefix,
            RunnableWithParameter callback, boolean runCallBackInUIThread, String format, boolean removeAplha)
            throws IOException {

        if (format == null)
            format = "png";

        if (removeAplha) {
            // remove alpha channel
            im = CoreImage.create(im).removeAlpha().getAwt();
        }

        // create a temp file
        File imFile = new File(
                FileUtils.generateUniqueFileName(imagePrefix == null ? "image" : imagePrefix, format));
        ImageIO.write(im, format, imFile);

        program.execute(imFile.getAbsolutePath());

        // add file to watcher thread
        return INSTANCE.addWatchedFile(imFile, callback, true, runCallBackInUIThread);
    }

    private static String getEditorPath(String type) {
        String editorPath = UtilsPlugin.getDefault().getPreferenceStore().getString(type);
        if (!(new File(editorPath).exists()))
            throw new IllegalArgumentException();
        return UtilsPlugin.getDefault().getPreferenceStore().getString(type);
    }

    public static FileInfo open3rdPartyEditor(String editorPath, String fileAbsolutePath, String imageDisplayName,
            RunnableWithParameter callback, boolean runCallBackInUIThread) throws IOException {

        if (IMediaConstants.PREF_BITMAP_EDITOR.equals(editorPath)) {
            editorPath = getEditorPath(IMediaConstants.PREF_BITMAP_EDITOR);
        } else if (IMediaConstants.PREF_VECTOR_EDITOR.equals(editorPath)) {
            editorPath = getEditorPath(IMediaConstants.PREF_VECTOR_EDITOR);
        } else if (IMediaConstants.PREF_SOUND_EDITOR.equals(editorPath)) {
            editorPath = getEditorPath(IMediaConstants.PREF_SOUND_EDITOR);
        }
        // determine which use from extension
        String extension = FileUtils.getExtension(fileAbsolutePath).toLowerCase().trim();

        if (editorPath == null) {
            try {
                if (IFileConstants.FILE_EXT_SVG.equals(extension))
                    editorPath = getEditorPath(IMediaConstants.PREF_VECTOR_EDITOR);
                else if ("wav".equals(extension))
                    editorPath = getEditorPath(IMediaConstants.PREF_SOUND_EDITOR);
                else
                    editorPath = getEditorPath(IMediaConstants.PREF_BITMAP_EDITOR);
            } catch (Exception e) {
            }
        }

        // no need to launch the process if it's not yet defined
        if (editorPath == null || editorPath.trim().length() == 0) {
            throw new IllegalArgumentException("Editor not defined");
        }

        String sourceFileName = fileAbsolutePath;
        // make a copy of the file and pass it to the filechangewatchthread
        File sourceFile = new File(sourceFileName);

        String extensions = FileUtils.getExtension(fileAbsolutePath);

        String destinationFileName = FileUtils
                .generateUniqueFileName(imageDisplayName == null ? "image" : imageDisplayName, extensions);
        File destinationFile = new File(destinationFileName);

        copy(sourceFile, destinationFile);

        boolean isSvg = false;
        if (IFileConstants.FILE_EXT_SVG.equals(extension)) {
            isSvg = true;
        }
        if (isSvg) {
            try {
                Document document = XmlUtil.parse(destinationFile);
                SvgUtil.fixDocTypeProblem(document);
                XmlUtil.write(document, destinationFile);
                isSvg = false;
            } catch (Exception e) {

                e.printStackTrace();
            }

        }

        Runtime.getRuntime().exec(editorPath + " " + destinationFile.getAbsolutePath());

        // add file to watcher thread
        return INSTANCE.addWatchedFile(destinationFile, callback, true, runCallBackInUIThread);
    }

    public static FileInfo open3rdPartyProgram(Program program, String fileAbsolutePath, String imageDisplayName,
            RunnableWithParameter callback, boolean runCallBackInUIThread) throws IOException {

        // determine which use from extension
        String extension = FileUtils.getExtension(fileAbsolutePath).toLowerCase().trim();

        String sourceFileName = fileAbsolutePath;
        // make a copy of the file and pass it to the filechangewatchthread
        File sourceFile = new File(sourceFileName);

        String extensions = FileUtils.getExtension(fileAbsolutePath);

        String destinationFileName = FileUtils
                .generateUniqueFileName(imageDisplayName == null ? "image" : imageDisplayName, extensions);
        File destinationFile = new File(destinationFileName);

        copy(sourceFile, destinationFile);

        boolean isSvg = false;
        if (IFileConstants.FILE_EXT_SVG.equals(extension)) {
            isSvg = true;
        }
        if (isSvg) {
            try {
                Document document = XmlUtil.parse(destinationFile);
                SvgUtil.fixDocTypeProblem(document);
                XmlUtil.write(document, destinationFile);
                isSvg = false;
            } catch (Exception e) {

                e.printStackTrace();
            }

        }

        program.execute(destinationFile.getAbsolutePath());

        // add file to watcher thread
        return INSTANCE.addWatchedFile(destinationFile, callback, true, runCallBackInUIThread);
    }

    public static FileInfo open3rdPartyVectorEditor(String editorPath, String imageFileName, String imagePrefix,
            RenderedImage image, Runnable callback, boolean runCallBackInUIThread) throws IOException {

        if (editorPath == null || IMediaConstants.PREF_VECTOR_EDITOR.equals(editorPath)) {
            editorPath = getEditorPath(IMediaConstants.PREF_VECTOR_EDITOR);
        }

        if (editorPath == null || editorPath.trim().length() == 0) {
            throw new IllegalArgumentException("Editor not defined.");
        }

        // create a temp file
        File imFile = new File(FileUtils.generateUniqueFileName(imagePrefix == null ? "image" : imagePrefix,
                IFileConstants.FILE_EXT_SVG));

        if (!imageFileName.toLowerCase().endsWith(IFileConstants.FILE_EXT_DOTSVG)) {

            DOMImplementation impl = SVGDOMImplementation.getDOMImplementation();
            String svgNS = SVGDOMImplementation.SVG_NAMESPACE_URI;
            Document doc = impl.createDocument(svgNS, IFileConstants.FILE_EXT_SVG, null);

            // get the root element (the svg element)
            Element svgRoot = doc.getDocumentElement();

            // set the width and height attribute on the root svg element
            svgRoot.setAttributeNS(null, "width", "100%");
            svgRoot.setAttributeNS(null, "height", "100%");
            svgRoot.setAttributeNS(null, "preserveAspectRatio", "xMidYMid meet");
            svgRoot.setAttributeNS(null, "version", "1.0");
            svgRoot.setAttributeNS(null, "viewBox", "0 0 " + image.getWidth() + " " + image.getHeight());
            svgRoot.setAttributeNS(null, "zoomAndPan", "magnify");

            OutputStream ostream = new FileOutputStream(imFile);
            Writer out = new OutputStreamWriter(ostream, "UTF-8");
            DOMUtilities.writeDocument(doc, out);
            out.close();
            ostream.close();
        } else {
            copy(new File(imageFileName), imFile);

            String extension = FileUtils.getExtension(imFile).toLowerCase().trim();
            boolean isSvg = false;
            if (IFileConstants.FILE_EXT_SVG.equals(extension)) {
                isSvg = true;
            }
            if (isSvg) {
                try {
                    Document document = XmlUtil.parse(imFile);
                    SvgUtil.fixDocTypeProblem(document);
                    XmlUtil.write(document, imFile);
                    isSvg = false;
                } catch (Exception e) {

                    e.printStackTrace();
                }

            }

        }

        Runtime.getRuntime().exec(new String[] { editorPath, imFile.getAbsolutePath() }, null,
                getWorkDir(editorPath));

        // add file to watcher thread
        return INSTANCE.addWatchedFile(imFile, callback, true, runCallBackInUIThread);
    }

    public static void displayThirdPartyEditorMisssingErrorMessageBox() {
        IBrandingManager branding = BrandingExtensionManager.getBrandingManager();
        Image image = null;
        if (branding != null) {
            image = branding.getIconImageDescriptor().createImage();
        }
        MessageDialog dialog = new MessageDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell(),
                Messages.FileChangeWatchThread_editorSettingsError, image,
                Messages.FileChangeWatchThread_editorError, 1,
                new String[] { IDialogConstants.OK_LABEL, IDialogConstants.CANCEL_LABEL }, 0);
        dialog.open();
        if (image != null) {
            image.dispose();
        }
    }

    public static void copy(File source, File dest) throws IOException {
        FileUtils.copyFile(source, dest);
    }
}