Package org.locationtech.udig.project.ui

Source Code of org.locationtech.udig.project.ui.AnimationUpdater

/**
*
*/
package org.locationtech.udig.project.ui;

import java.awt.Rectangle;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;

import org.locationtech.udig.project.internal.ProjectPlugin;
import org.locationtech.udig.project.preferences.PreferenceConstants;
import org.locationtech.udig.project.render.displayAdapter.IMapDisplay;
import org.locationtech.udig.project.ui.internal.ProjectUIPlugin;
import org.locationtech.udig.project.ui.render.displayAdapter.ViewportPane;

import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.swt.widgets.Display;

/**
* Responsible for updating the viewport when animations need their next animation frame to be displayed.
*
* @author jeichar
*/
public class AnimationUpdater {

    private static boolean testing=false;
    final List<IAnimation> animations=new CopyOnWriteArrayList<IAnimation>();
    private ViewportPane display;
    private short frameInterval;

    public AnimationUpdater( ViewportPane display, short frameInterval) {
        this.display = display;
        this.frameInterval=frameInterval;
    }
   
    public void run() {
        List<IAnimation> toRemove = new LinkedList<IAnimation>();
        for ( Iterator<IAnimation> iter=animations.iterator(); iter.hasNext(); ){
            IAnimation anim=iter.next();
            if( anim.hasNext())
                anim.nextFrame();
            else{
                anim.setValid(false);
                anim.dispose();
                toRemove.add(anim);
            }
           
            animations.removeAll(toRemove);
            if( isTesting() ){
                try {
                    anim.run(new NullProgressMonitor());
                } catch (Exception e) {
                    throw (RuntimeException) new RuntimeException( ).initCause( e );
                }
            }
        }
        if( !isTesting() )
            display.repaint();
           
        if( animations.size()==0 ){
            remove(this);
        }else{
            final RunUpdaters next = next();
            if (next != null) {
                final short elapseTime;
                if (next.frameinterval <= frameInterval) {
                    elapseTime=next.frameinterval;
                }else{
                    elapseTime=(short)(next.frameinterval-frameInterval);
                }
                runTimer(elapseTime, next);
            }
        }
    }

   
    /**
     * Should only be used for testing
     */
    static boolean isTesting() {
        return testing;
    }

    /**
     * should only be used for testing purposes.
     *
     * @param testing
     */
    public static void setTesting(boolean isTesting){
        testing=isTesting;
    }
    private static void runTimer(final short frameInterval, final RunUpdaters next ) {
        final Display display;
        if (Display.getCurrent() == null) {
            display = Display.getDefault();
            display.asyncExec(new Runnable(){
                public void run() {
                    Display.getCurrent().timerExec(frameInterval, next);
                }
            });
        } else {
            display = Display.getCurrent();
            display.timerExec(frameInterval, next);
        }
    }

    private RunUpdaters next() {
        synchronized (AnimationUpdater.class) {
            SortedMap<Short, List<AnimationUpdater>> tailMap = displayToTaskMap.tailMap(frameInterval);
            if( tailMap.isEmpty() ){
                if( displayToTaskMap.size()>0 )
                    return new RunUpdaters( displayToTaskMap.firstKey() );
                return new RunUpdaters(frameInterval);
            }
           
            return new RunUpdaters(tailMap.keySet().iterator().next());
        }
    }
   
    private static class RunUpdaters implements Runnable{
       
        private short frameinterval;

        public RunUpdaters( short frameInterval ) {
            this.frameinterval=frameInterval;
        }

        public void run() {
            synchronized (AnimationUpdater.class) {
                List<AnimationUpdater> updaters = displayToTaskMap.get(frameinterval);
                for( AnimationUpdater updater : updaters ) {
                    if (!updater.display.isDisposed() && updater.display.isVisible()){
                        updater.run();
                    }else{
                      //we want to remove this updater
                      for (IAnimation anim: updater.getAnimations()){
                        anim.setValid(false);
                        anim.dispose();
                      }
                      updater.remove(updater);
                    }
                }
            }
        }
    }

    private void remove( AnimationUpdater updater ) {
        synchronized (AnimationUpdater.class) {
            List<AnimationUpdater> hashMap = displayToTaskMap.get(updater.frameInterval);
            if( hashMap!=null ){
                hashMap.remove(updater);
                if( hashMap.isEmpty() )
                    displayToTaskMap.remove(frameInterval);
            }
        }
    }

    // Locked by AnimationUpdater.class
    private static TreeMap<Short, List<AnimationUpdater>> displayToTaskMap=new TreeMap<Short, List<AnimationUpdater>>();

//    private static final Timer TIMER = new Timer("Animation Timer", true); //$NON-NLS-1$
    private static final short MIN_INTERVAL=100;
    public synchronized static void runTimer( IMapDisplay mapDisplay, IAnimation animation ) {
        if!ProjectPlugin.getPlugin().getPreferenceStore().getBoolean(PreferenceConstants.P_SHOW_ANIMATIONS)){
            return;
        }
       
        if (!(mapDisplay instanceof ViewportPane)) {
            ProjectUIPlugin.log("Map Display provided is not a ViewportPane and therefore does not" //$NON-NLS-1$
                    + " support animation", new RuntimeException()); //$NON-NLS-1$
            return;
        }
       
        short frameInterval = calculateFrameInterval(animation);
        ViewportPane viewport=(ViewportPane) mapDisplay;
       
        // Try to get the map from animationInterval to the AnimationUpdater for that interval
        List<AnimationUpdater> tasks=displayToTaskMap.get(frameInterval);
        boolean requiresRun=false;
       
        if (tasks == null) {
            requiresRun=true;
            tasks = new CopyOnWriteArrayList<AnimationUpdater>();
            displayToTaskMap.put(frameInterval, tasks);
        }

        AnimationUpdater updater = findUpdater(frameInterval,  viewport);
        viewport.addDrawCommand(animation);

        if (updater != null) {
            updater.getAnimations().add(animation);
        } else {
            AnimationUpdater task = new AnimationUpdater((ViewportPane) viewport, frameInterval);
            task.getAnimations().add(animation);
            tasks.add(task);
            if( requiresRun ){
                runTimer(frameInterval, new RunUpdaters(frameInterval));
            }
        }
       
        Rectangle bounds = animation.getValidArea();
        if( bounds==null ){
            viewport.repaint();
        }else{
            viewport.repaint(bounds.x, bounds.y, bounds.width, bounds.height);
        }
    }

    private static AnimationUpdater findUpdater( short frameInterval2, ViewportPane viewport ) {
        List<AnimationUpdater> updaters = displayToTaskMap.get(frameInterval2);
        if( updaters==null)
            return null;
        for( AnimationUpdater updater : updaters ) {
            if( updater.display==viewport)
                return updater;
        }
        return null;
    }

    private static short calculateFrameInterval( IAnimation animation ) {
        short frameInterval = animation.getFrameInterval();

        int i = (frameInterval - (MIN_INTERVAL * (frameInterval / MIN_INTERVAL)));
        frameInterval = (short) (frameInterval - i);
        if (frameInterval < MIN_INTERVAL)
            frameInterval = MIN_INTERVAL;
        return frameInterval;
    }

    /**
     * @return Returns the animations.
     */
    public List<IAnimation> getAnimations() {
        return animations;
    }

    /**
     * @return Returns the frameInterval.
     */
    public short getFrameInterval() {
        return frameInterval;
    }
}
TOP

Related Classes of org.locationtech.udig.project.ui.AnimationUpdater

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.