All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.pepsoft.util.SubProgressReceiver Maven / Gradle / Ivy

The newest version!
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.pepsoft.util;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 *
 * @author pepijn
 */
public class SubProgressReceiver implements ProgressReceiver {
    public SubProgressReceiver(ProgressReceiver progressReceiver, float offset, float extent) throws OperationCancelled {
        this(progressReceiver, null, offset, extent);
    }

    public SubProgressReceiver(ProgressReceiver progressReceiver, String message, float offset, float extent) throws OperationCancelled {
        if ((offset < 0.0f) || (offset > 1.0f) || (extent <= 0.0f)) {
            throw new IllegalArgumentException();
        }
        this.progressReceiver = progressReceiver;
        this.offset = offset;
        this.extent = extent;
        creationTrace = new Throwable("Creation");
        lastMessage = message;
    }

    /**
     * Adds an additional progress receiver, to which the
     * {@link #setProgress(float)}, {@link #setMessage(java.lang.String)},
     * {@link #done()} and {@link #exceptionThrown(java.lang.Throwable)} methods
     * will be forwarded (without remapping the progress). Note that recursive
     * invocations of {@code setMessage()}, {@code exceptionThrown()}
     * and {@code done()} are not reported.
     */
    public synchronized void addListener(ProgressReceiver listener) {
        if (listeners == null) {
            listeners = new ArrayList<>();
        }
        listeners.add(listener);
    }
    
    public synchronized void removeListener(ProgressReceiver listener) {
        listeners.remove(listener);
    }

    public ProgressReceiver getParent() {
        return progressReceiver;
    }

    public synchronized String getLastMessage() {
        return lastMessage;
    }

    public Throwable getCreationTrace() {
        return creationTrace;
    }

    // ProgressReceiver

    @Override
    public void setProgress(float progress) throws OperationCancelled {
        if (! reportedToParent) {
            progressReceiver.subProgressStarted(this);
            reportedToParent = true;
        }
        float parentProgress = offset + progress * extent;
        if (parentProgress < 0.0f) {
            progressReceiver.setProgress(0.0f);
        } else if (parentProgress > 1.0f) {
            progressReceiver.setProgress(1.0f);
        } else {
            progressReceiver.setProgress(parentProgress);
        }
        synchronized (this) {
            if (listeners != null) {
                for (ProgressReceiver listener: listeners) {
                    listener.setProgress(progress);
                }
            }
        }
    }

    @Override
    public void exceptionThrown(Throwable exception) {
        if (! recursiveCall.get().get()) {
            recursiveCall.get().set(true);
            try {
                progressReceiver.exceptionThrown(exception);
                synchronized (this) {
                    if (listeners != null) {
                        for (ProgressReceiver listener: listeners) {
                            listener.exceptionThrown(exception);
                        }
                    }
                }
            } finally {
                recursiveCall.get().set(false);
            }
        } else {
            progressReceiver.exceptionThrown(exception);
        }
    }

    @Override
    public synchronized void done() {
        if (listeners != null) {
            for (ProgressReceiver listener: listeners) {
                listener.done();
            }
        }
    }

    @Override
    public void setMessage(String message) throws OperationCancelled {
        if (! recursiveCall.get().get()) {
            recursiveCall.get().set(true);
            try {
                if (! reportedToParent) {
                    progressReceiver.subProgressStarted(this);
                    reportedToParent = true;
                }
                progressReceiver.setMessage(message);
                synchronized (this) {
                    if (listeners != null) {
                        for (ProgressReceiver listener: listeners) {
                            listener.setMessage(message);
                        }
                    }
                }
                synchronized (this) {
                    lastMessage = message;
                }
            } finally {
                recursiveCall.get().set(false);
            }
        } else {
            progressReceiver.setMessage(message);
        }
    }

    @Override
    public void checkForCancellation() throws OperationCancelled {
        progressReceiver.checkForCancellation();
    }

    @Override
    public void reset() {
        throw new UnsupportedOperationException("Not supported");
    }

    @Override
    public void subProgressStarted(SubProgressReceiver subProgressReceiver) throws OperationCancelled {
        progressReceiver.subProgressStarted(subProgressReceiver);
    }

    private final ProgressReceiver progressReceiver;
    private final float offset, extent;
    private final Throwable creationTrace;
    private List listeners;
    private String lastMessage;
    private boolean reportedToParent;

    private static final ThreadLocal recursiveCall = new ThreadLocal() {
        @Override
        protected AtomicBoolean initialValue() {
            return new AtomicBoolean(false);
        }
    };
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy