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

Java tutorial

Introduction

Here is the source code for com.nokia.s60tools.remotecontrol.screen.ui.view.ScreenView.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.ByteArrayInputStream;

import java.util.Arrays;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTException;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IWorkbenchActionConstants;

import com.nokia.s60tools.hticonnection.exceptions.ServiceShutdownException;
import com.nokia.s60tools.hticonnection.services.HTIScreenMode;
import com.nokia.s60tools.hticonnection.services.HTIServiceFactory;
import com.nokia.s60tools.hticonnection.services.IScreenCaptureService;
import com.nokia.s60tools.hticonnection.services.ScreenCaptureData;
import com.nokia.s60tools.remotecontrol.RemoteControlActivator;
import com.nokia.s60tools.remotecontrol.actions.OpenPreferencePageAction;
import com.nokia.s60tools.remotecontrol.keyboard.IKeyboardMediator;
import com.nokia.s60tools.remotecontrol.preferences.RCPreferencePage;
import com.nokia.s60tools.remotecontrol.preferences.RCPreferences;
import com.nokia.s60tools.remotecontrol.resources.ImageKeys;
import com.nokia.s60tools.remotecontrol.resources.Messages;
import com.nokia.s60tools.remotecontrol.screen.ui.actions.OpenKeyboardAction;
import com.nokia.s60tools.remotecontrol.screen.ui.actions.SaveMultiScreenshotsAction;
import com.nokia.s60tools.remotecontrol.screen.ui.actions.SaveSingleScreenshotAction;
import com.nokia.s60tools.remotecontrol.screen.ui.actions.ZoomAction;
import com.nokia.s60tools.remotecontrol.screen.ui.actions.ZoomAction.ZoomFactor;
import com.nokia.s60tools.remotecontrol.ui.AbstractUiFractionComposite;
import com.nokia.s60tools.remotecontrol.ui.views.main.MainView;
import com.nokia.s60tools.remotecontrol.util.ImageHelper;
import com.nokia.s60tools.remotecontrol.util.RemoteControlConsole;

/**
 * This class comprises the screen view of the Remote Control
 * application.
 */
public class ScreenView extends AbstractUiFractionComposite implements PaintListener {

    /**
     * We can get view ID at runtime once the view is instantiated, but we
     * also need static access to ID in order to be able to invoke the view.
     */
    public static final String ID = "com.nokia.s60tools.remotecontrol.screen.ui.view.ScreenView"; //$NON-NLS-1$

    //
    // Actions
    //   

    /**
     * Open preferences action
     */
    private static Action preferencesAction;

    /**
     * Save single screenshot action
     */
    private static Action saveSingleScreenshotAction;

    /**
     * Save multiple sequential screenshots action
     */
    private static SaveMultiScreenshotsAction saveMultiScreenshotsAction;

    /**
     * Show keyboard view action
     */
    private static Action keyboardAction;

    //
    // Members.
    //

    /**
     * Screen canvas
     */
    private Canvas screenCanvas;

    /**
     * Default scroll bars for screen canvas.
     */
    private ScrolledComposite screenScrollBarDefault;

    /**
     * Scroll bars for screen canvas.
     * Used with ZOOM_TO_WIDTH zoom factor.
     */
    private ScrolledComposite screenScrollBarVertical;

    /**
     * Scroll bars for screen canvas. 
     * Used with ZOOM_TO_HEIGHT zoom factor.
     */
    private ScrolledComposite screenScrollBarHorizontal;

    /**
     * Layout used to change between different scroll bars.
     */
    private StackLayout scrollBarLayout;

    /**
     * Thread for capturing screen
     */
    private volatile Thread screenCaptureThread;

    /**
     * Thread for saving screenshots.
     */
    private ScreenSaverThread screenSaverThread;

    /**
     * Main view
     */
    private final MainView mainView;

    /**
     * Property change listener
     */
    private IPropertyChangeListener listener = null;

    /**
     * Listener for resize events.
     */
    private ControlListener resizeListener = null;

    /**
     * Touch screen handler
     */
    private TouchScreenHandler touchScreenHandler = null;

    /**
     * Keyboard mediator to delegate events to.
     */
    private IKeyboardMediator keyboardMediator;

    /**
     * Instance of this class. Used for sending key events
     * to keyboard mediator.
     */
    private ScreenView instance;

    /**
     * Previously captured image data from the device screen.
     */
    byte[] previousImageData;

    //
    // Constants
    //

    /**
     * Screen is captured in png format.
     */
    private static final String IMAGE_TYPE = "image/png"; //$NON-NLS-1$

    /**
     * Amount that scroll bars are incremented by default.
     */
    private static final int DEFAULT_SCROLL_INCREMENT = 100;

    /**
     * Settings for current screen.
     */
    private ScreenSettings screenSettings;

    /**
     * The constructor.
     * @param parentComposite Parent
     * @param style Style bits
     * @param mainView MainView
     */
    public ScreenView(Composite parentComposite, int style, MainView mainView) {
        super(parentComposite, style);
        this.mainView = mainView;
        this.instance = this;
        screenSettings = new ScreenSettings();
        screenSettings.getPreferences();
        createPropertyChangeListener();
        // Dummy screen mode, so that valid value is returned before first screen capture.
        screenSettings.setScreenMode(new HTIScreenMode(0, 0, 0, 0, 0, 0));

        // Starting thread to capture screens from the device.
        screenSaverThread = new ScreenSaverThread(this);
        screenSaverThread.start();
        screenCaptureThread = new screenCaptureThread();
        screenCaptureThread.start();

        // Action button states needs to be updated after all resources have been created.
        updateActionButtonStates();
        createResizeListener();

        // Register to keyboard mediator
        keyboardMediator = RemoteControlActivator.getKeyboardMediator();
        keyboardMediator.registerKeyboardMediatorClient(this);
    }

    /**
     * Create listener to listen screen resize messages. 
     */
    private void createResizeListener() {

        resizeListener = new ControlAdapter() {
            public void controlResized(ControlEvent e) {
                // ScreenCanvas needs to be redrawn to keep screen zoomed.
                screenCanvas.redraw();
            }
        };

        addControlListener(resizeListener);
    }

    /**
     * Create change listener to prefstore preferences 
     */
    private void createPropertyChangeListener() {

        // Call getPreferences() when prefstore values are changed
        listener = new IPropertyChangeListener() {
            public void propertyChange(PropertyChangeEvent event) {
                screenSettings.getPreferences();
            }
        };

        RCPreferences.addPropertyChangeListener(listener);
    }

    /**
     * Create main menu actions in here. The same actions
     * can be also used to populate context menus, if needed.
     */
    private void createMainMenuActions() {
        preferencesAction = new OpenPreferencePageAction(Messages.getString("ScreenView.Open_Preferences_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Open_Preferences_Tooltip"), IAction.AS_PUSH_BUTTON, //$NON-NLS-1$
                ImageKeys.IMG_PREFERENCES, RCPreferencePage.Tabs.SCREENCAPTURE);
        saveMultiScreenshotsAction = new SaveMultiScreenshotsAction(this);
        saveSingleScreenshotAction = new SaveSingleScreenshotAction(
                Messages.getString("ScreenView.Save_Screenshot_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Save_Screenshot_Action_Tooltip"), this); //$NON-NLS-1$
        keyboardAction = new OpenKeyboardAction(Messages.getString("ScreenView.Open_Keyboard_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Open_Keyboard_Action_Tooltip")); //$NON-NLS-1$
    }

    /**
     * This method fills action bars (no need for further modifications).
     */
    protected void fillViewActionBars() {
        IActionBars bars = mainView.getActionBars();
        fillViewMainMenu(bars.getMenuManager());
        fillViewToolBar(bars.getToolBarManager());
    }

    /**
     * View's main menu is populated in here.
     * @param manager Menu manager instance.
     */
    private void fillViewMainMenu(IMenuManager manager) {
        manager.removeAll();
        manager.add(saveMultiScreenshotsAction);
        manager.add(saveSingleScreenshotAction);
        manager.add(keyboardAction);
        manager.add(preferencesAction);
        manager.update(true);
    }

    /**
     * View's tool bar is populated in here.
     * @param manager Tool bar instance.
     */
    private void fillViewToolBar(IToolBarManager manager) {
        manager.removeAll();
        manager.add(saveMultiScreenshotsAction);
        manager.add(saveSingleScreenshotAction);
        manager.add(preferencesAction);
        manager.update(true);
    }

    /**
     * Hooks context menu to the current view.
     */
    protected void hookContextMenu() {
        MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
        menuMgr.setRemoveAllWhenShown(true);
        menuMgr.addMenuListener(new IMenuListener() {
            public void menuAboutToShow(IMenuManager manager) {
                ScreenView.this.fillContextMenu(manager);
            }
        });
        Menu menu = menuMgr.createContextMenu(screenCanvas);
        screenCanvas.setMenu(menu);
        screenScrollBarDefault.setMenu(menu);
        screenScrollBarHorizontal.setMenu(menu);
        screenScrollBarVertical.setMenu(menu);
        mainView.registerContextMenu(menuMgr, new ISelectionProvider() {
            public void addSelectionChangedListener(ISelectionChangedListener listener) {
            }

            public ISelection getSelection() {
                return new StructuredSelection(screenCanvas);
            }

            public void removeSelectionChangedListener(ISelectionChangedListener listener) {
            }

            public void setSelection(ISelection selection) {
            }
        });
    }

    /**
     * Fills context menu.
     * @param manager used to fill menu.
     */
    private void fillContextMenu(IMenuManager manager) {
        manager.add(new ZoomAction(this, Messages.getString("ScreenView.Zoom_To_Fit_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Zoom_To_Fit_Tooltip"), ZoomFactor.ZOOM_TO_FIT)); //$NON-NLS-1$
        manager.add(new ZoomAction(this, Messages.getString("ScreenView.Zoom_To_Height_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Zoom_To_Height_Tooltip"), ZoomFactor.ZOOM_TO_HEIGHT)); //$NON-NLS-1$
        manager.add(new ZoomAction(this, Messages.getString("ScreenView.Zoom_To_Width_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Zoom_To_Width_Tooltip"), ZoomFactor.ZOOM_TO_WIDTH)); //$NON-NLS-1$
        manager.add(new ZoomAction(this, Messages.getString("ScreenView.Zoom_50%_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Zoom_50%_Tooltip"), ZoomFactor.ZOOM_TO_50_PERCENT)); //$NON-NLS-1$
        manager.add(new ZoomAction(this, Messages.getString("ScreenView.Zoom_100%_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Zoom_100%_Tooltip"), ZoomFactor.ZOOM_TO_100_PERCENT)); //$NON-NLS-1$
        manager.add(new ZoomAction(this, Messages.getString("ScreenView.Zoom_200%_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Zoom_200%_Tooltip"), ZoomFactor.ZOOM_TO_200_PERCENT)); //$NON-NLS-1$
        manager.add(new ZoomAction(this, Messages.getString("ScreenView.Zoom_400%_Action"), //$NON-NLS-1$
                Messages.getString("ScreenView.Zoom_400%_Tooltip"), ZoomFactor.ZOOM_TO_400_PERCENT)); //$NON-NLS-1$
        // Other plug-ins can contribute actions here
        manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
    }

    /**
     * Allows other classes to update content description.
     * @param newContentDescription New description.
     */
    public void updateDescription(String newContentDescription) {
        mainView.updateDescription(newContentDescription);
    }

    /**
     * Allows other classes to set default content description.
     */
    public void setDefaultDescription() {
        mainView.setDefaultDescription();
    }

    /**
     * The view should refresh all its UI components in this method.
     */
    public void refresh() {
        // Currently there is no need for refresh, because no data model views.
    }

    /* (non-Javadoc)
     * @see org.eclipse.ui.part.WorkbenchPart#dispose()
     */
    public void dispose() {
        super.dispose();

        // Stopping screensaver thread
        screenSaverThread.stopThread();

        // Ending capture thread.
        screenCaptureThread = null;

        // Images need to be disposed.
        if (ScreenSettings.getScreenImage() != null) {
            ScreenSettings.setScreenImage(null, null);
        }
        // Remove property listener
        if (listener != null) {
            RCPreferences.removePropertyChangeListener(listener);
        }

        // Remove touch screen handler.
        if (touchScreenHandler != null) {
            screenCanvas.removeMouseListener(touchScreenHandler);
            touchScreenHandler.dispose();
        }

        // Unregister from keyboard mediator
        keyboardMediator.unregisterKeyboardMediatorClient(this);
    }

    /**
     * Makes necessary changes to context menu and action bars.
     */
    public void setAsActiveView() {
        hookContextMenu();
        fillViewActionBars();
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent)
     */
    public void paintControl(PaintEvent e) {
        if (ScreenSettings.getScreenImage() != null) {

            // Getting necessary variables.
            Color backgroundColor = e.gc.getBackground();
            Rectangle clientArea = screenCanvas.getClientArea();
            Image image = new Image(Display.getCurrent(), clientArea.width, clientArea.height);
            GC gc = new GC(image);

            // Drawing background with original color for image.
            // Background and image is drawn to different GC to prevent flickering.
            gc.setBackground(backgroundColor);
            gc.fillRectangle(clientArea);
            drawScreenImage(gc);

            // Drawing image with its correct size to screen.
            e.gc.drawImage(image, 0, 0);

            // Disposing created objects.
            gc.dispose();
            image.dispose();
        } else {
            // Filling screen with background color.
            Rectangle clientArea = screenCanvas.getClientArea();
            e.gc.fillRectangle(clientArea);

            drawFirstScreenHelp(e);
        }
    }

    /**
     * Draws current screen shot to given GC object.
     * @param gc Graphics object where current screen image is drawn.
     */
    private void drawScreenImage(GC gc) {

        Image screenShot = ScreenSettings.getScreenShotCopy();
        Rectangle screenSize = screenShot.getBounds();
        Rectangle clientArea = ((ScrolledComposite) scrollBarLayout.topControl).getClientArea();

        // Calculating destination width and height based on zoom factor. 

        double zoomPercent = getZoomPercent(screenSize, clientArea);
        screenSettings.setZoomPercent(zoomPercent);

        int destWidth = (int) (screenSize.width * zoomPercent);
        int destHeight = (int) (screenSize.height * zoomPercent);

        // Drawing the image.
        gc.drawImage(screenShot, 0, 0, screenSize.width, screenSize.height, 0, 0, destWidth, destHeight);
        screenShot.dispose();

        // Setting screenCanvas size to make scroll bars show correctly.
        screenCanvas.setSize(destWidth, destHeight);
    }

    /**
     * Calculates percentage that screen image needs to be zoomed based on
     * currently selected zoom factor.
     * @param screenSize Size of the screen image.
     * @param clientArea Size of the are where image is drawn.
     * @return Percentage of how much image needs to be zoomed.
     */
    private double getZoomPercent(Rectangle screenSize, Rectangle clientArea) {

        // Calculating how much screen is zoomed. 

        double zoomPercent;

        switch (screenSettings.getZoomFactor()) {
        case ZOOM_TO_FIT:
            double maxWidthFactor = (double) clientArea.width / screenSize.width;
            double maxHeightFactor = (double) clientArea.height / screenSize.height;
            if (maxHeightFactor < maxWidthFactor) {
                // Height factor is smaller, so height limits zooming.
                zoomPercent = maxHeightFactor;
            } else {
                // Width factor is smaller, so width limits zooming.
                zoomPercent = maxWidthFactor;
            }
            break;
        case ZOOM_TO_HEIGHT:
            zoomPercent = (double) clientArea.height / screenSize.height;
            break;
        case ZOOM_TO_WIDTH:
            zoomPercent = (double) clientArea.width / screenSize.width;
            break;
        case ZOOM_TO_50_PERCENT:
            zoomPercent = 0.5;
            break;
        case ZOOM_TO_100_PERCENT:
            zoomPercent = 1.0;
            break;
        case ZOOM_TO_200_PERCENT:
            zoomPercent = 2.0;
            break;
        case ZOOM_TO_400_PERCENT:
            zoomPercent = 4.0;
            break;
        default:
            // Using normal size as default.
            zoomPercent = 1.0;
            break;
        }

        return zoomPercent;
    }

    /**
     * Draws start-up information text for user.
     * @param event Event that contains control for painting to screen.
     */
    private void drawFirstScreenHelp(PaintEvent event) {
        event.gc.drawString(Messages.getString("ScreenView.FirstTimeUse_Help_Text1"), 10, 10); //$NON-NLS-1$
        event.gc.drawString(Messages.getString("ScreenView.FirstTimeUse_Help_Text2"), 10, 50); //$NON-NLS-1$
        event.gc.drawString(Messages.getString("ScreenView.FirstTimeUse_Help_Text3"), 10, 70); //$NON-NLS-1$

        // Setting size to screen canvas, so that scroll bars are shown if necessary.
        final int helpTextLength = 300;
        final int helpTextHeight = 100;
        screenCanvas.setSize(helpTextLength, helpTextHeight);
    }

    /**
     * Captures image from phone and saves it to screenImage.
     */
    private boolean captureImage() {
        IScreenCaptureService service = HTIServiceFactory
                .createScreenCaptureService(RemoteControlConsole.getInstance());

        try {
            // Getting the current screen mode.
            HTIScreenMode screenMode = service.getScreenMode(screenSettings.getTimeoutTime());
            // If screen mode has changed, take full screen capture.
            if (!screenMode.equals(screenSettings.getScreenMode())) {
                previousImageData = null;
            }
            screenSettings.setScreenMode(screenMode);

            // Capturing the image.
            // If image not captured before, take a full screen capture.
            byte[] imagedata = null;
            if (previousImageData == null) {
                service.resetScreenDelta(screenSettings.getTimeoutTime());
                imagedata = service.captureFullScreenDelta(IMAGE_TYPE, screenSettings.getColorChoice(),
                        screenSettings.getTimeoutTime()).getImageData();
                previousImageData = imagedata;
            } else { // If image captured earlier...
                // ...capture only changed part of the image.
                ScreenCaptureData captureData = service.captureFullScreenDelta(IMAGE_TYPE,
                        screenSettings.getColorChoice(), screenSettings.getTimeoutTime());

                // If image not empty (changes have been made since last screen delta).
                if (captureData.getImageData().length > 0) {
                    // Add captured delta image on top of previous screen image.
                    imagedata = ImageHelper.overlayImage(previousImageData, captureData.getImageData(),
                            captureData.getTopLeftX(), captureData.getTopLeftY(), IMAGE_TYPE);
                } else {
                    // No need to change the screen image.
                    imagedata = previousImageData;
                }

                // Replace previous image with changed image combination.
                previousImageData = imagedata;
            }
            // Converting bytes to image.
            ByteArrayInputStream is = new ByteArrayInputStream(imagedata);
            Image image = new Image(Display.getCurrent(), is);

            byte[] previousImageData = ScreenSettings.getImageData();

            // Setting new image in use.
            ScreenSettings.setScreenImage(image, imagedata);

            if (screenSettings.isSavingAllScreenshots()) {
                if (screenSettings.getImagesSaved() == 0 || !Arrays.equals(imagedata, previousImageData)) {
                    // Only first and new images are saved.
                    saveCurrentScreenDefaultValues();
                }
            }

            updateActionButtonStates();

            // Screen captured successfully.
            return true;

        } catch (ServiceShutdownException e) {
            // Services have been purposely shut down. No need to report error.
            return false;
        } catch (Exception e) {
            // Problem is reported already via RemoteControlConsole given as parameter to service.
            return false;
        }
    }

    /**
     * Thread that takes care of updating screen.
     */
    private class screenCaptureThread extends Thread {

        public void run() {
            Thread thisThread = Thread.currentThread();
            boolean isScreenCaptured;

            while (thisThread == screenCaptureThread) {
                try {
                    isScreenCaptured = captureImage();

                    // Updating image only if one was successfully captured.
                    if (isScreenCaptured) {
                        Runnable updateScreenImage = new Runnable() {
                            public void run() {
                                // Testing that screenImage is still there and it is possible to redraw.
                                if (ScreenSettings.getScreenImage() != null) {
                                    try {
                                        screenCanvas.redraw();
                                    } catch (SWTException e) {
                                        // Catching exceptions that arise when plug-in is being
                                        // disposed and thread is not yet stopped.
                                    }
                                }
                            }
                        };
                        // UI updates from background threads has to be queued
                        // into UI thread in order not to cause invalid thread access
                        Display.getDefault().asyncExec(updateScreenImage);
                    }

                    Thread.sleep(screenSettings.getRefreshTime());

                } catch (InterruptedException e) {
                    e.printStackTrace();
                    RemoteControlConsole.getInstance()
                            .println("screenCaptureThread.run() InterruptedException: " + e.getMessage() //$NON-NLS-1$
                                    , RemoteControlConsole.MSG_ERROR);
                } catch (Exception e) {
                    e.printStackTrace();
                    RemoteControlConsole.getInstance().println("screenCaptureThread.run() Error: " + e.getMessage() //$NON-NLS-1$
                            , RemoteControlConsole.MSG_ERROR);
                }
            }
        }
    }

    /* (non-Javadoc)
     * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent)
     */
    public void mouseUp(MouseEvent e) {
        // Not needed.
    }

    /* (non-Javadoc)
     * @see com.nokia.s60tools.remotecontrol.ui.AbstractUiFractionComposite#createControls()
     */
    @Override
    protected void createControls() {
        try {
            //
            // Actions invoked by content providers may set enable/disable
            // states for the actions, therefore all the action has to be
            // created before creating the controls. This makes sure that
            // it is safe to refer to all the actions after this point.
            //
            createMainMenuActions();

            //
            // Creating controls
            //

            // Creating layout data
            GridData gridData = new GridData();
            gridData.grabExcessHorizontalSpace = true;
            gridData.grabExcessVerticalSpace = true;
            gridData.horizontalAlignment = SWT.FILL;
            gridData.verticalAlignment = SWT.FILL;

            scrollBarLayout = new StackLayout();
            this.setLayout(scrollBarLayout);

            // Creating scroll bars for different zoom types.
            screenScrollBarDefault = new ScrolledComposite(this, SWT.H_SCROLL | SWT.V_SCROLL);
            screenScrollBarDefault
                    .setSize(screenScrollBarDefault.computeSize(getClientArea().width, getClientArea().height));
            screenScrollBarVertical = new ScrolledComposite(this, SWT.V_SCROLL);
            screenScrollBarHorizontal = new ScrolledComposite(this, SWT.H_SCROLL);

            // NO_BACKGROUND is used to reduce flickering.
            // Because of this, it is needed to draw whole image before drawing it to screen.
            screenCanvas = new Canvas(screenScrollBarDefault, SWT.NO_BACKGROUND);
            screenCanvas.setSize(screenScrollBarDefault.getSize());
            touchScreenHandler = new TouchScreenHandler(this);
            screenCanvas.addMouseListener(touchScreenHandler);
            screenCanvas.addPaintListener(this);
            screenCanvas.setLayoutData(gridData);

            // Scroll bars need to be configured after screenCanvas has been created.
            configureScrollBars();

            //
            // Doing other initializations that may refer to the component
            // that has been created above.
            //      

            // Listening key events coming from keyboard
            KeyListener pcKeyboardListener = new KeyListener() {
                public void keyPressed(KeyEvent e) {
                    // Non character (e.g. Alt, Ctrl) key events are not forwarded
                    if (e.character != '\0') {
                        if (keyboardMediator != null) {
                            keyboardMediator.characterKeyPressed(instance, e.character);
                        }
                    }
                }

                public void keyReleased(KeyEvent e) {
                    // Not used
                }
            };
            screenCanvas.addKeyListener(pcKeyboardListener);

        } catch (Exception e) {
            e.printStackTrace();
            RemoteControlConsole.getInstance()
                    .println(Messages.getString("ScreenView.Failed_Create_Screen_View_ConsoleMsg") + e.getMessage() //$NON-NLS-1$
                            , RemoteControlConsole.MSG_ERROR);
        }
    }

    /**
     * Configures scroll bars used around screenCanvas.
     */
    private void configureScrollBars() {
        scrollBarLayout.topControl = screenScrollBarDefault;

        screenScrollBarVertical.setContent(screenCanvas);
        screenScrollBarVertical.setAlwaysShowScrollBars(true);
        screenScrollBarVertical.getVerticalBar().setPageIncrement(DEFAULT_SCROLL_INCREMENT);
        screenScrollBarVertical.getVerticalBar().setIncrement(DEFAULT_SCROLL_INCREMENT);

        screenScrollBarHorizontal.setContent(screenCanvas);
        screenScrollBarHorizontal.setAlwaysShowScrollBars(true);
        screenScrollBarHorizontal.getHorizontalBar().setPageIncrement(DEFAULT_SCROLL_INCREMENT);
        screenScrollBarHorizontal.getHorizontalBar().setIncrement(DEFAULT_SCROLL_INCREMENT);

        screenScrollBarDefault.setContent(screenCanvas);
        screenScrollBarDefault.getVerticalBar().setPageIncrement(DEFAULT_SCROLL_INCREMENT);
        screenScrollBarDefault.getVerticalBar().setIncrement(DEFAULT_SCROLL_INCREMENT);
        screenScrollBarDefault.getHorizontalBar().setPageIncrement(DEFAULT_SCROLL_INCREMENT);
        screenScrollBarDefault.getHorizontalBar().setIncrement(DEFAULT_SCROLL_INCREMENT);
    }

    /* (non-Javadoc)
     * @see com.nokia.s60tools.remotecontrol.ui.AbstractUiFractionComposite#createLayout()
     */
    protected Layout createLayout() {
        GridLayout gridLayout = new GridLayout();
        gridLayout.numColumns = 2;
        return gridLayout;
    }

    /* (non-Javadoc)
     * @see com.nokia.s60tools.remotecontrol.ui.AbstractUiFractionComposite#createLayoutData()
     */
    protected Object createLayoutData() {
        // No default layout data.
        return null;
    }

    /**
     * Sets enabled/disabled states for actions commands
     * on this view, based on the current application state.
     * This method should be called whenever an operation is
     * started or stopped that might have effect on action 
     * button states.
     */
    public void updateActionButtonStates() {
        if (!screenSettings.isSavingAllScreenshots()) {
            saveMultiScreenshotsAction.setSaving(false);
        }

        // Setting save single screenshot action.
        if (ScreenSettings.getScreenImage() == null || screenSettings.isSavingAllScreenshots()) {
            saveSingleScreenshotAction.setEnabled(false);
        } else {
            saveSingleScreenshotAction.setEnabled(true);
        }

        // Setting save multi screenshot action.
        saveMultiScreenshotsAction.setEnabled(ScreenSettings.getScreenImage() != null);
    }

    /**
     * Updates zooming for current screen.
     */
    public void updateZoom() {

        // Setting correct scroll bars for new zoom factor.

        switch (screenSettings.getZoomFactor()) {
        case ZOOM_TO_HEIGHT:
            if (!screenCanvas.setParent(screenScrollBarHorizontal)) {
                // Set parent not supported. Using default scroll bars.
                break;
            }
            scrollBarLayout.topControl = screenScrollBarHorizontal;
            this.layout();
            break;
        case ZOOM_TO_WIDTH:
            if (!screenCanvas.setParent(screenScrollBarVertical)) {
                // Set parent not supported. Using default scroll bars. 
                break;
            }
            scrollBarLayout.topControl = screenScrollBarVertical;
            this.layout();
            break;
        default:
            if (!screenCanvas.setParent(screenScrollBarDefault)) {
                // Set parent not supported. Using default scroll bars. 
                break;
            }
            scrollBarLayout.topControl = screenScrollBarDefault;
            this.layout();
            break;
        }

        // Updating screen image

        if (ScreenSettings.getScreenImage() != null) {
            Runnable updateScreenImage = new Runnable() {
                public void run() {
                    // Testing that screenImage is still there and it is possible to redraw.
                    if (ScreenSettings.getScreenImage() != null) {
                        try {
                            screenCanvas.redraw();
                        } catch (SWTException e) {
                            // Catching exceptions that arise when plug-in is being
                            // disposed and thread is not yet stopped.
                        }
                    }
                }
            };
            // UI updates from background threads has to be queued
            // into UI thread in order not to cause invalid thread access
            Display.getDefault().asyncExec(updateScreenImage);
        }
    }

    /**
     * Saves current screen with values defined preferences.
     */
    public void saveCurrentScreenDefaultValues() {
        screenSaverThread.addImageToQueue(ScreenSettings.getImageData());
    }

    /**
     * Returns current settings for showing the screen.
     * @return Current settings for the screen.
     */
    public ScreenSettings getScreenSettings() {
        return screenSettings;
    }
}