net.tourbook.photo.internal.gallery.MT20.FullScreenPhotoGallery.java Source code

Java tutorial

Introduction

Here is the source code for net.tourbook.photo.internal.gallery.MT20.FullScreenPhotoGallery.java

Source

/*******************************************************************************
 * Copyright (C) 2005, 2013  Wolfgang Schramm and Contributors
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation version 2 of the License.
 *
 * 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, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 *******************************************************************************/
package net.tourbook.photo.internal.gallery.MT20;

import net.tourbook.common.UI;
import net.tourbook.common.util.Util;
import net.tourbook.photo.IPhotoGalleryProvider;
import net.tourbook.photo.IPhotoPreferences;
import net.tourbook.photo.IPhotoProvider;
import net.tourbook.photo.Photo;
import net.tourbook.photo.PhotoGallery;
import net.tourbook.photo.PhotoSelection;
import net.tourbook.photo.internal.Messages;

import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.layout.GridLayoutFactory;
import org.eclipse.jface.resource.ColorRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseWheelListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.events.ShellListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.ToolBar;

public class FullScreenPhotoGallery implements IPhotoGalleryProvider {

    private static final int GALLERY_DEFAULT_HEIGHT = 150;
    private static final int GALLERY_MIN_IMAGE_SIZE = 40;
    private static final int GALLERY_MAX_IMAGE_SIZE = 1000;

    private static final String STATE_FULL_SCREEN_PHOTO_GALLERY_HEIGHT = "STATE_FULL_SCREEN_PHOTO_GALLERY_HEIGHT"; //$NON-NLS-1$

    private ControlAnimation _photoGalleryAnimation;

    private IDialogSettings _state;

    private AllControlsListener _allControlsListener;

    private GalleryMT20 _sourceGallery;
    private PhotoGallery _photoGallery;
    private FullScreenImageViewer _fullScreenImageViewer;

    private int _displayedPhotosHash;
    private int _displayedItemIndex;

    private boolean _isLinkPhotoDisplayed;

    private ToolBarManager _galleryToolbarManager;

    /*
     * UI controls
     */
    private Shell _fullScreenShell;
    private Shell _galleryShell;

    private ToolBar _galleryToolbarControl;
    private Spinner _spinnerResizeImage;

    private Control _galleryContainer;
    private Composite _containerFooter;

    /**
     * This listener is added to ALL widgets within the tooltip shell.
     */
    private class AllControlsListener implements Listener {
        public void handleEvent(final Event event) {
            onAllControlsEvent(event);
        }

    }

    public class ControlAnimation implements Runnable {

        /**
         * how long each tick is when fading in/out (in ms)
         */
        //      private static final int   FADE_TIME_INTERVAL      = UI.IS_OSX ? 10 : 10;
        private final int FADE_TIME_INTERVAL = UI.IS_OSX ? 10 : 10;

        /**
         * Number of steps when fading in
         */
        private static final int FADE_IN_STEPS = 20;

        /**
         * Number of steps when fading out
         */
        private static final int FADE_OUT_STEPS = 10;

        private static final int ALPHA_OPAQUE = 0xff;

        private Display _display;
        private Shell _shell;

        private boolean _isFadeIn;
        private boolean _isFadeOut;

        private int _fadeAlpha;

        public ControlAnimation(final Shell shell, final Control control) {

            _shell = shell;
            _display = shell.getDisplay();
        }

        public void fadeIn() {

            if (_isFadeIn) {
                // fade in is already started
                return;
            }

            if (_isFadeOut) {

                // stop fade out and start with current alpha

                _fadeAlpha = _shell.getAlpha();
            } else {
                _fadeAlpha = 0;
            }

            _isFadeIn = true;
            _isFadeOut = false;

            run();
        }

        public void fadeOut() {

            if (_isFadeOut) {
                // fade out is already started
                return;
            }

            _fadeAlpha = _shell.getAlpha();

            _isFadeIn = false;
            _isFadeOut = true;

            run();
        }

        @Override
        public void run() {

            if (_shell == null || _shell.isDisposed()) {
                return;
            }

            final boolean isVisible = _shell.isVisible();

            if (_isFadeIn) {

                final int fadeInStep = ALPHA_OPAQUE / FADE_IN_STEPS;

                int newAlpha = _fadeAlpha + fadeInStep;
                if (newAlpha > ALPHA_OPAQUE) {
                    newAlpha = ALPHA_OPAQUE;
                }

                // set alpha before shell is displayed
                _shell.setAlpha(newAlpha);

                if (isVisible == false) {
                    _shell.setVisible(true);
                    _shell.setActive();
                }

                final int currentAlpha = _shell.getAlpha();
                if (currentAlpha != newAlpha) {

                    // platform do not support alpha (e.g. Ubuntu 12.04 in my test system)

                    _shell.setAlpha(ALPHA_OPAQUE);
                    _isFadeIn = false;

                } else {

                    _fadeAlpha = currentAlpha;

                    if (currentAlpha == ALPHA_OPAQUE) {

                        // reached end of fade in
                        _isFadeIn = false;

                    } else {

                        // start timer for a neww fade in
                        _display.timerExec(FADE_TIME_INTERVAL, this);
                    }
                }

            } else if (_isFadeOut) {

                if (isVisible == false) {
                    _isFadeOut = false;
                    return;
                }

                final int fadeOutStep = ALPHA_OPAQUE / FADE_OUT_STEPS;

                int newAlpha = _fadeAlpha - fadeOutStep;
                if (newAlpha < 0) {
                    newAlpha = 0;
                }

                _shell.setAlpha(newAlpha);

                final int currentAlpha = _shell.getAlpha();
                if (currentAlpha != newAlpha) {

                    // platform do not support alpha (e.g. Ubuntu 12.04 in my test system)

                    _shell.setAlpha(0);

                    _shell.setVisible(false);
                    _isFadeOut = false;

                } else {

                    _fadeAlpha = currentAlpha;

                    if (currentAlpha == 0) {

                        // reached end of fade in

                        _shell.setVisible(false);
                        _isFadeOut = false;

                    } else {

                        // start timer for a neww fade out
                        _display.timerExec(FADE_TIME_INTERVAL, this);
                    }
                }
            }
        }
    }

    public FullScreenPhotoGallery(final Shell fullScreenShell, final GalleryMT20 sourceGallery,
            final FullScreenImageViewer fullScreenImageViewer, final IDialogSettings state) {

        _fullScreenShell = fullScreenShell;
        _sourceGallery = sourceGallery;
        _fullScreenImageViewer = fullScreenImageViewer;
        _state = state;

        createUI();

        _photoGalleryAnimation = new ControlAnimation(_galleryShell, _photoGallery.getGallery());

        _allControlsListener = new AllControlsListener();
        addListenerToAllControls(_galleryShell);

        addFullScreenListener();
    }

    private void addFullScreenListener() {

        _fullScreenShell.addDisposeListener(new DisposeListener() {

            @Override
            public void widgetDisposed(final DisposeEvent e) {
                onDispose();
            }
        });
    }

    /**
     * ########################### Recursive #########################################<br>
     * <p>
     * Add listener to all controls
     * <p>
     * ########################### Recursive #########################################<br>
     * 
     * @param control
     */
    private void addListenerToAllControls(final Control control) {

        control.addListener(SWT.KeyDown, _allControlsListener);

        if (control instanceof Composite) {
            final Control[] children = ((Composite) control).getChildren();
            for (final Control child : children) {
                addListenerToAllControls(child);
            }
        }
    }

    private void addShellListener() {

        _galleryShell.addControlListener(new ControlListener() {

            @Override
            public void controlMoved(final ControlEvent e) {
            }

            @Override
            public void controlResized(final ControlEvent e) {
                onResize(e);
            }
        });

        _galleryShell.addShellListener(new ShellListener() {

            @Override
            public void shellActivated(final ShellEvent e) {
            }

            @Override
            public void shellClosed(final ShellEvent e) {
            }

            @Override
            public void shellDeactivated(final ShellEvent e) {
                hideGallery();
            }

            @Override
            public void shellDeiconified(final ShellEvent e) {
            }

            @Override
            public void shellIconified(final ShellEvent e) {
                hideGallery();
            }
        });
    }

    private void createUI() {

        _galleryShell = new Shell(SWT.NO_TRIM | SWT.ON_TOP);

        final Rectangle fsShellSize = _fullScreenShell.getBounds();

        _galleryShell.setBounds(fsShellSize.x, fsShellSize.y, fsShellSize.width, GALLERY_DEFAULT_HEIGHT);
        //      _galleryShell.setLayout(new FillLayout());
        GridLayoutFactory.fillDefaults().spacing(0, 10).applyTo(_galleryShell);
        //      _galleryShell.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_MAGENTA));

        addShellListener();

        createUI_10_Gallery(_galleryShell);
    }

    private void createUI_10_Gallery(final Shell parent) {

        final Composite container = new Composite(parent, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, true).applyTo(container);
        GridLayoutFactory.fillDefaults().numColumns(1).spacing(0, 0).applyTo(container);
        //      container.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_GREEN));
        {

            _photoGallery = new PhotoGallery(_state);

            _photoGallery.hideActionSorting();
            _photoGallery.hideActionFiltering();
            _photoGallery.setShowCustomActionBar();

            _photoGallery.createPhotoGallery(container, SWT.H_SCROLL, this);

            /**
             * Prevent to open pref dialog, when it's opened it would close this tooltip and the
             * pref dialog is hidden -->> APP IS FREEZING !!!
             */
            _photoGallery.setShowOtherShellActions(false);

            createUI_20_ActionBar(_photoGallery.getCustomActionBarContainer());

            createUI_30_Footer(container);
        }

        fillActionBar();

        /*
         * set fullscreen image viewer in the photo gallery to the fullscreen image viewer in the
         * source gallery, this is a bit a a hack
         */
        _photoGallery.setFullScreenImageViewer(_sourceGallery.getFullScreenImageViewer());

        _galleryContainer = _photoGallery.getGalleryContainer();
    }

    private void createUI_20_ActionBar(final Composite parent) {

        GridLayoutFactory.fillDefaults().applyTo(parent);

        final Composite container = new Composite(parent, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(container);
        GridLayoutFactory.fillDefaults().numColumns(2).applyTo(container);
        //      container.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
        {
            /*
             * create gallery toolbar
             */
            _galleryToolbarControl = new ToolBar(container, SWT.FLAT);
            GridDataFactory.fillDefaults()//
                    .align(SWT.END, SWT.FILL).grab(true, false).applyTo(_galleryToolbarControl);

            /*
             * spinner: resize image
             */
            _spinnerResizeImage = new Spinner(container, SWT.BORDER);
            GridDataFactory.fillDefaults() //
                    .applyTo(_spinnerResizeImage);
            _spinnerResizeImage.setMinimum(GALLERY_MIN_IMAGE_SIZE);
            _spinnerResizeImage.setMaximum(GALLERY_MAX_IMAGE_SIZE);
            _spinnerResizeImage
                    .setToolTipText(UI.IS_OSX ? Messages.FullScreen_ImageViewer_Spinner_ResizeImage_Tooltip_OSX
                            : Messages.FullScreen_ImageViewer_Spinner_ResizeImage_Tooltip);

            _spinnerResizeImage.addSelectionListener(new SelectionAdapter() {

                @Override
                public void widgetSelected(final SelectionEvent e) {
                    onSelectResizeImage();
                }
            });
            _spinnerResizeImage.addMouseWheelListener(new MouseWheelListener() {
                public void mouseScrolled(final MouseEvent event) {
                    Util.adjustSpinnerValueOnMouseScroll(event);
                    onSelectResizeImage();
                }
            });

        }
    }

    private void createUI_30_Footer(final Composite parent) {

        _containerFooter = new Composite(parent, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, false).applyTo(_containerFooter);
        GridLayoutFactory.fillDefaults()//
                .numColumns(1).spacing(0, 0).extendedMargins(0, 0, 5, 0).applyTo(_containerFooter);
        //      _containerFooter.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_RED));
        {
            //         final Label label = new Label(_containerFooter, SWT.NONE);
            //         GridDataFactory.fillDefaults().applyTo(label);
            //         label.setText("Madlkfjasljdfasjdflasf");
        }

    }

    private void fillActionBar() {

        /*
         * fill gallery toolbar
         */
        _galleryToolbarManager = new ToolBarManager(_galleryToolbarControl);

        // must be called after the custom action bar is created
        _photoGallery.createActionBar();

        _galleryToolbarManager.update(false);
    }

    @Override
    public IStatusLineManager getStatusLineManager() {
        return null;
    }

    @Override
    public IToolBarManager getToolBarManager() {
        return _galleryToolbarManager;
    }

    private void hideGallery() {

        if (_galleryShell == null || _galleryShell.isVisible() == false) {
            return;
        }

        _photoGallery.stopLoadingImages();

        _photoGalleryAnimation.fadeOut();

        _fullScreenImageViewer.activate();
    }

    private void onAllControlsEvent(final Event event) {

        final int keyCode = event.keyCode;

        if (keyCode == SWT.ESC) {

            // hide full screen gallery
            hideGallery();

        } else {

            final char keyCharacterShowPhotoGallery = Messages.FullScreenImageViewer_KeyCharacter_ShowPhotoGallery
                    .charAt(0);

            if (event.character == keyCharacterShowPhotoGallery) {

                // hide with the same key as opening full screen gallery
                hideGallery();
            }
        }
    }

    private void onDispose() {

        if (_galleryShell != null) {

            saveState();

            _galleryShell.close();
        }
    }

    private void onResize(final ControlEvent e) {

        //      final Point shellSize = _galleryShell.getSize();
        //      final Point gallerySize = _photoGallery.getGallery().getSize();
        //
        //      final int trimX = shellSize.y - gallerySize.y;
        //
        //      System.out.println(UI.timeStampNano()
        //            + " onResize()\ttrim: "
        //            + trimX
        //            + "  shell: "
        //            + shellSize.y
        //            + "  gallery: "
        //            + gallerySize.y);
    }

    private void onSelectResizeImage() {

        setGallerySize(_spinnerResizeImage.getSelection());
    }

    @Override
    public void registerContextMenu(final String menuId, final MenuManager menuManager) {
    }

    void restoreState() {

        final int imageSize = Util.getStateInt(_state, STATE_FULL_SCREEN_PHOTO_GALLERY_HEIGHT,
                GALLERY_DEFAULT_HEIGHT);
        _spinnerResizeImage.setSelection(imageSize);

        updateColors(true);

        _photoGallery.restoreState();
    }

    void saveState() {

        _state.put(STATE_FULL_SCREEN_PHOTO_GALLERY_HEIGHT, _spinnerResizeImage.getSelection());

        _photoGallery.saveState();
    }

    /**
     * Set shell size from gallery size.
     * 
     * @param imageSize
     */
    private void setGallerySize(final int imageSize) {

        final Point shellSize = _galleryShell.getSize();
        final Point gallerySize = _photoGallery.getGallery().getSize();

        final int trimX = shellSize.y - gallerySize.y;

        _galleryShell.setSize(shellSize.x, trimX + imageSize);
    }

    @Override
    public void setSelection(final PhotoSelection photoSelection) {

        _isLinkPhotoDisplayed = photoSelection.isLinkPhotoDisplayed;

        _fullScreenImageViewer.showImage(photoSelection);
    }

    boolean showImages(final int mouseY, final int displayedItemIndex) {

        if (mouseY == 0) {

            // show gallery

            _displayedItemIndex = displayedItemIndex;

            showImages_10_InGallery();

            return true;

        } else {

            // hide gallery

            hideGallery();

            return false;
        }
    }

    private void showImages_10_InGallery() {

        final IPhotoProvider photoProvider = _sourceGallery.getPhotoProvider();
        final Photo[] photoWrapper = photoProvider.getSortedAndFilteredPhotos();

        final int photosHash = photoWrapper.hashCode();
        final String galleryPositionKey = photosHash + "_FullScreenPhotoGallery";//$NON-NLS-1$

        /**
         * !!! gallery shell must be visible before any gallery methods are called, otherwise the
         * gallery is hidden and not fully initialized !!!!
         */

        final boolean isShellVisible = _galleryShell.isVisible();
        if (isShellVisible == false) {
            _photoGalleryAnimation.fadeIn();
        }

        /**
         * check if new images should be displayed, this check is VERY IMPORTANT otherwise this can
         * be a performance hog
         */
        if (_displayedPhotosHash != photosHash) {

            _displayedPhotosHash = photosHash;

            final Control gallery = _photoGallery.getGallery();

            final Point gallerySize = gallery.getSize();

            if (gallerySize.x == 0) {

                /**
                 * setting size is a bit tricky, I found no other way
                 */

                // height must be set with the layout
                final GridData gd = (GridData) _galleryContainer.getLayoutData();
                gd.heightHint = _spinnerResizeImage.getSelection();

                // with must be set from the shell size
                gd.widthHint = _galleryShell.getSize().x;

                _galleryShell.pack(true);
            }

            _photoGallery.showImages(photoWrapper, galleryPositionKey, _isLinkPhotoDisplayed);
        }

        // show photo in the gallery which is displayed in the full screen viewer
        _photoGallery.selectItem(_displayedItemIndex, galleryPositionKey);
    }

    private void updateColors(final boolean isRestore) {

        final ColorRegistry colorRegistry = JFaceResources.getColorRegistry();
        final Color fgColor = colorRegistry.get(IPhotoPreferences.PHOTO_VIEWER_COLOR_FOREGROUND);
        final Color bgColor = colorRegistry.get(IPhotoPreferences.PHOTO_VIEWER_COLOR_BACKGROUND);
        final Color selectionFgColor = colorRegistry.get(IPhotoPreferences.PHOTO_VIEWER_COLOR_SELECTION_FOREGROUND);

        final Color noFocusSelectionFgColor = Display.getCurrent()
                .getSystemColor(SWT.COLOR_TITLE_INACTIVE_BACKGROUND);

        _photoGallery.updateColors(fgColor, bgColor, selectionFgColor, noFocusSelectionFgColor, isRestore);

        _containerFooter.setBackground(bgColor);
    }

}