/*******************************************************************************
* GenPlay, Einstein Genome Analyzer
* Copyright (C) 2009, 2014 Albert Einstein College of Medicine
*
* 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, either version 3 of the License, or
* (at your option) any later version.
*
* 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, see <http://www.gnu.org/licenses/>.
* Authors: Julien Lajugie <julien.lajugie@einstein.yu.edu>
* Nicolas Fourel <nicolas.fourel@einstein.yu.edu>
* Eric Bouhassira <eric.bouhassira@einstein.yu.edu>
*
* Website: <http://genplay.einstein.yu.edu>
******************************************************************************/
package edu.yu.einstein.genplay.gui.action;
import java.awt.event.ActionEvent;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import javax.swing.JRootPane;
import javax.swing.SwingWorker;
import edu.yu.einstein.genplay.core.operationPool.OperationPool;
import edu.yu.einstein.genplay.dataStructure.enums.AlleleType;
import edu.yu.einstein.genplay.exception.ExceptionManager;
import edu.yu.einstein.genplay.gui.dialog.exceptionDialog.WarningReportDialog;
import edu.yu.einstein.genplay.gui.event.operationProgressEvent.OperationProgressEvent;
import edu.yu.einstein.genplay.gui.event.operationProgressEvent.OperationProgressListener;
import edu.yu.einstein.genplay.gui.mainFrame.MainFrame;
import edu.yu.einstein.genplay.gui.statusBar.StatusBar;
import edu.yu.einstein.genplay.gui.statusBar.Stoppable;
import edu.yu.einstein.genplay.gui.trackList.TrackListPanel;
import edu.yu.einstein.genplay.util.Utils;
/**
* Action that starts a SwingWorker thread
* @author Julien Lajugie
* @param <T> typed of the value returned by the action
*/
public abstract class TrackListActionWorker<T> extends TrackListAction implements OperationProgressListener, Stoppable {
/**
* Private inner class that extends SwingWorker<T, Void>.
* Processes the action.
* @author Julien Lajugie
*/
private class PooledActionWorker extends SwingWorker<T, Void> {
@Override
final protected T doInBackground() throws Exception {
synchronized (MainFrame.class) {
if (MainFrame.getInstance().isLocked()) {
return null;
} else {
MainFrame.getInstance().lock();
}
}
OperationPool.getInstance().addOperationProgressListener(TrackListActionWorker.this);
return processAction();
}
@Override
final protected void done() {
try {
Utils.garbageCollect();
getStatusBar().actionStop("Operation Done");
doAtTheEnd(this.get());
} catch (Exception e) {
if ((e.getCause() instanceof InterruptedException) || (e instanceof CancellationException)) {
getStatusBar().actionStop("Operation Aborted");
} else {
getStatusBar().actionStop("Error");
ExceptionManager.getInstance().caughtException(Thread.currentThread(), e, "An unexpected error occurred during the operation");
}
} finally {
OperationPool.getInstance().removeOperationProgressListener(TrackListActionWorker.this);
MainFrame.getInstance().unlock();
if ((!WarningReportDialog.getInstance().isVisible())) {
MainFrame.getInstance().setVisible(true);
}
}
}
}
private static final long serialVersionUID = 1383058897700926018L; // generated ID
private int currentStep = 1; // current step of the action
protected SwingWorker<T, Void> worker; // worker that will process the action
protected String genomeName = null; // genome name for a multi genome project
protected AlleleType alleleType = null; // allele type for a multi genome project
protected CountDownLatch latch = null;
/**
* Public constructor
*/
public TrackListActionWorker() {
super();
}
/**
* Method called at the end of the action.
* Can be extended to define the action to do at the end.
* @param actionResult result returned by the action method
*/
protected void doAtTheEnd(T actionResult) {}
/**
* @return the {@link JRootPane} of the {@link TrackList}
*/
@Override
protected JRootPane getRootPane() {
return MainFrame.getInstance().getTrackListPanel().getRootPane();
}
/**
* @return the status bar of the application
*/
private StatusBar getStatusBar() {
return MainFrame.getInstance().getStatusBar();
}
/**
* Shortcut for MainFrame.getInstance().getTrackList()
* @return the track list of the project
*/
@Override
protected TrackListPanel getTrackListPanel() {
return MainFrame.getInstance().getTrackListPanel();
}
/**
* Notifies that an action starts
* Must be called right before the computation starts
* @param description description of the action
* @param stepCount number of steps needed to complete the action
* @param stoppable must be set to true if the action can be stopped. False otherwise
*/
protected void notifyActionStart(String description, int stepCount, boolean stoppable) {
currentStep = 1;
if (stoppable) {
getStatusBar().actionStart(description, stepCount, this);
} else {
getStatusBar().actionStart(description, stepCount, null);
}
}
/**
* Notifies the status bar that an action ends.
*/
protected void notifyActionStop() {
getStatusBar().actionStop("Operation Done");
}
@Override
public void operationProgressChanged(OperationProgressEvent evt) {
StatusBar statusBar = getStatusBar();
if (evt.getState() == OperationProgressEvent.STARTING) {
// when a step start
statusBar.setProgress(currentStep, 0);
} else if (evt.getState() == OperationProgressEvent.IN_PROGRESS) {
// when a step is in progress
statusBar.setProgress(currentStep, (int)evt.getCompletion());
} else if (evt.getState() == OperationProgressEvent.COMPLETE) {
// when a step is done
statusBar.setProgress(currentStep, 100);
currentStep++;
}
}
/**
* Specifies the action to process
* @return the result of the action
* @throws Exception
*/
protected abstract T processAction() throws Exception;
@Override
public void stop() {
worker.cancel(true);
OperationPool.getInstance().stopPool();
Utils.garbageCollect();
}
@Override
public final void trackListActionPerformed(ActionEvent e) {
if (!MainFrame.getInstance().isLocked()) {
try {
worker = new PooledActionWorker();
worker.execute();
} catch (Exception err) {
ExceptionManager.getInstance().caughtException(err);
}
}
}
}