com.nokia.s60tools.remotecontrol.screen.ui.view.ScreenSaverThread.java Source code

Java tutorial

Introduction

Here is the source code for com.nokia.s60tools.remotecontrol.screen.ui.view.ScreenSaverThread.java

Source

/*
* Copyright (c) 2009 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.s60tools.remotecontrol.screen.ui.view;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.OutputStream;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.jface.preference.PreferenceDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.dialogs.PreferencesUtil;

import com.nokia.s60tools.remotecontrol.RemoteControlActivator;
import com.nokia.s60tools.remotecontrol.preferences.RCPreferencePage;
import com.nokia.s60tools.remotecontrol.preferences.RCPreferences;
import com.nokia.s60tools.remotecontrol.resources.Messages;
import com.nokia.s60tools.remotecontrol.ui.dialogs.RemoteControlMessageBox;

/**
 * This class is used for saving screen shots based on preferences.
 * Stores images to queue and saves them sequentially with correct file name.
 */
public class ScreenSaverThread extends Thread {

    /**
     * Queue keeping images track on images that need to be saved later.
     */
    private LinkedBlockingQueue<byte[]> imageQueue;

    /**
     * Boolean if this thread should be running.
     */
    private boolean running = true;

    /**
     * Screen view.
     */
    private final ScreenView screenView;

    /**
     * Amount if images that will be saved before asking if user wants to continue
     * saving more images.
     */
    private final int IMAGES_SAVED_BEFORE_NOTE = 1000;

    /**
     * Constructor.
     * @param screenView Screen view.
     */
    public ScreenSaverThread(ScreenView screenView) {
        this.screenView = screenView;
        imageQueue = new LinkedBlockingQueue<byte[]>();
    }

    /**
     * Adds image to the queue from which it will be saved to file system later.
     * @param image to be saved.
     */
    public synchronized void addImageToQueue(byte[] image) {
        if (running) {
            imageQueue.add(image);
        }
    }

    /**
     * Stops the thread.
     */
    public void stopThread() {
        running = false;

        imageQueue.clear();
    }

    /**
     * Saves image to file system using values that are in preferences.
     * @param image Image to be saved.
     * @return True if save succeeded. False otherwise.
     */
    private boolean saveImageDefaultValues(byte[] image) throws IOException {

        // Checking the path in preferences.
        File filePath = new File(RCPreferences.getScreenShotSaveLocation());
        if (filePath.isDirectory()) {
            // Image can be saved, because folder is ok.
            File fileNameWithPath = getNextFileName(filePath);
            saveImage(fileNameWithPath, image);
            return true;
        } else {
            // Image cannot be saved, because folder was not found.
            String msg = Messages.getString("ScreenSaverThread.InvalidPath_ErrorMsg"); //$NON-NLS-1$

            errorMsgBoxRunnable msgBoxRunnable = new errorMsgBoxRunnable(msg);

            Display.getDefault().asyncExec(msgBoxRunnable);
        }
        return false;
    }

    /**
     * Open Remote control preferences page
     */
    private void openPreferencePage() {

        PreferenceDialog dialog = PreferencesUtil.createPreferenceDialogOn(
                RemoteControlActivator.getCurrentlyActiveWbWindowShell(), RCPreferencePage.PAGE_ID, null, null);

        dialog.open();
    }

    /**
     * Gets next valid file name that can be used to save image.
     * Checks given directory if it already contains files with same name
     * and then creates new file name that doesn't exist.
     * @param directory Directory to be checked.
     * @return File name that can be used to save image.
     */
    private File getNextFileName(File directory) {
        String fileName = RCPreferences.getScreenshotFileName();

        // Getting files that have matching file name.
        FileFilter filter = new FileFilter(directory, fileName);
        String[] files = directory.list(filter);

        // Checking if there is already file with bigger index.
        int index = 0;
        for (String tmpFileName : files) {
            // Index can be extracted because only files which contain index get through filter.
            String fileIndex = tmpFileName.substring(tmpFileName.lastIndexOf('(') + 1,
                    tmpFileName.lastIndexOf(')'));
            int tmpIndex = Integer.parseInt(fileIndex);
            if (tmpIndex > index) {
                index = tmpIndex;
            }
        }

        // Making sure that file does not exist already.
        File nextFile;
        do {
            // Updating index to prevent using existing index. 
            index++;
            nextFile = new File(directory.getPath() + File.separator + fileName + "(" + index + ").png"); //$NON-NLS-1$ //$NON-NLS-2$
        } while (nextFile.exists());

        return nextFile;
    }

    /**
     * Saves given image with given file name/path.
     * @param fileName Name and path of file where image is saved.
     * @param imageData Image to be saved.
     */
    private void saveImage(File fileName, byte[] imageData) throws IOException {
        // Write file to disk

        OutputStream out = new FileOutputStream(fileName);
        out.write(imageData);
        out.close();
    }

    /* (non-Javadoc)
     * @see java.lang.Thread#run()
     */
    public void run() {

        byte[] image = null;
        while (running) {
            try {
                image = imageQueue.poll(50, TimeUnit.MILLISECONDS);

                if (image != null) {
                    // New image was found from queue, saving it.
                    if (saveImageDefaultValues(image)) {
                        screenView.getScreenSettings().imageSaved();
                        if (screenView.getScreenSettings().getImagesSaved() == IMAGES_SAVED_BEFORE_NOTE) {
                            // Pre-defined amount of images saved since starting saving.
                            // Showing error message from UI thread.
                            Runnable showErrorMessage = new Runnable() {
                                public void run() {
                                    String msg = IMAGES_SAVED_BEFORE_NOTE + Messages.getString(
                                            "ScreenSaverThread.SaveAllScreenshotsConfirmation_MessageText"); //$NON-NLS-1$
                                    RemoteControlMessageBox msgBox = new RemoteControlMessageBox(msg,
                                            SWT.YES | SWT.NO | SWT.ICON_QUESTION);

                                    int result = msgBox.open();
                                    if (result == SWT.NO) {
                                        stopSavingScreenshots();
                                    }
                                }
                            };
                            Display.getDefault().asyncExec(showErrorMessage);
                        }
                    }
                }

                image = null;

            } catch (final Exception e) {

                // Showing error message from UI thread.
                Runnable showErrorMessage = new Runnable() {
                    public void run() {
                        // Preventing more images to cause same error message.
                        stopSavingScreenshots();

                        String msg = Messages.getString("ScreenSaverThread.FailedToSaveImage_ErrorMsg1") //$NON-NLS-1$
                                + RCPreferences.getScreenShotSaveLocation()
                                + Messages.getString("ScreenSaverThread.FailedToSaveImage_ErrorMsg2") //$NON-NLS-1$
                                + e.getMessage();
                        RemoteControlMessageBox msgBox = new RemoteControlMessageBox(msg, SWT.ICON_ERROR);

                        msgBox.open();
                    }
                };
                Display.getDefault().asyncExec(showErrorMessage);

            }
        }
    }

    /**
     * Stops the save all screenshots action.
     */
    private void stopSavingScreenshots() {
        // Preventing more images to cause same error message.
        screenView.getScreenSettings().setSavingAllScreenshots(false);
        screenView.updateActionButtonStates();
        imageQueue.clear();
    }

    /**
     * Runnable for showing error message with option to show preferences page.
     */
    private class errorMsgBoxRunnable implements Runnable {

        /**
         * Message to be shown.
         */
        private final String msg;

        /**
         * Constructor.
         * @param msg Message that is shown to user.
         */
        public errorMsgBoxRunnable(String msg) {
            this.msg = msg;
        }

        /* (non-Javadoc)
         * @see java.lang.Runnable#run()
         */
        public void run() {
            // Preventing more images to cause same error message.
            stopSavingScreenshots();

            RemoteControlMessageBox msgBox = new RemoteControlMessageBox(msg, SWT.YES | SWT.NO | SWT.ICON_ERROR);

            int result = msgBox.open();

            // Opening preferences if Yes is selected.
            if (result == SWT.YES) {
                openPreferencePage();
            }
        }
    }

    /**
     * Filter that can be used to for getting indexed image files with
     * given name prefix.
     */
    private class FileFilter implements FilenameFilter {

        /**
         * Directory that is used to compare.
         */
        private final File defaultDir;
        /**
         * File name that is used to compare.
         */
        private final String defaultName;

        /**
         * Constructor.
         * @param defaultDir Directory that is used to compare.
         * @param defaultName File name that is used to compare.
         */
        public FileFilter(File defaultDir, String defaultName) {
            this.defaultDir = defaultDir;
            this.defaultName = defaultName;
        }

        /* (non-Javadoc)
         * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String)
         */
        public boolean accept(File dir, String name) {
            if (dir != defaultDir) {
                return false;
            }

            // Matches to e.g. defaultName(123).png
            String regex = "\\A" + defaultName + "\\([0-9]+\\)\\.png\\z"; //$NON-NLS-1$ //$NON-NLS-2$
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(name);
            if (matcher.find()) {
                return true;
            }
            return false;
        }
    }
}