/** * Copyright (c) 2010, 2013 Darmstadt University of Technology. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Marcel Bruch - initial API and implementation. */ package org.eclipse.recommenders.internal.models.rcp; import java.text.MessageFormat; import java.util.Map; import org.apache.commons.io.FileUtils; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.SubProgressMonitor; import org.eclipse.recommenders.internal.models.rcp.l10n.Messages; import org.eclipse.recommenders.models.DownloadCallback; import com.google.common.collect.Maps; /** * Callback to indicate progress on multiple sequential downloads. The callback works for a given number of downloads * and will split the monitored work on each of them. If less downloads are executed than expected, the callback can * finish the work to indicate a proper progress. Though it is recommended to call {@link #finish()} after all work is * done in any case. */ public class MultipleDownloadCallback extends DownloadCallback { private final Map<String, IProgressMonitor> downloads = Maps.newHashMap(); private boolean downloadSucceeded; private long lastTransferred; private int finishedWorkUnits; private final IProgressMonitor monitor; private final int maximumNumberOfDownloads; private final int workUnitsPerDownloadTask; private int workUnitsRemainder; public MultipleDownloadCallback(IProgressMonitor monitor, String message, int totalWorkUnits, int maximumNumberOfDownloads) { this.monitor = monitor; this.maximumNumberOfDownloads = maximumNumberOfDownloads; workUnitsPerDownloadTask = totalWorkUnits / maximumNumberOfDownloads; workUnitsRemainder = totalWorkUnits % maximumNumberOfDownloads; monitor.beginTask(message, totalWorkUnits); } @Override public synchronized void downloadInitiated(String path) { int workUnits = workUnitsPerDownloadTask; if (workUnitsRemainder >= 1) { workUnits++; } SubProgressMonitor subProgressMonitor = new SubProgressMonitor(monitor, workUnits); subProgressMonitor.beginTask(path, workUnits); downloads.put(path, subProgressMonitor); lastTransferred = 0; finishedWorkUnits = 0; } @Override public synchronized void downloadProgressed(String path, long transferred, long total) { IProgressMonitor submonitor = downloads.get(path); final String message; // If no total size is known, total might be -1. if (total >= transferred) { handleMonitorWorkForDownloadProgress(transferred, total, submonitor); message = createProgressMessage(transferred, total); } else { message = createProgressMessage(transferred); } submonitor.subTask(message); } private void handleMonitorWorkForDownloadProgress(long transferred, long total, IProgressMonitor submonitor) { long newTransferred = transferred - lastTransferred; lastTransferred = transferred; int workUnits = calculateWorkUnitsForDownloadProgress(newTransferred, total); finishedWorkUnits += workUnits; submonitor.worked(workUnits); } private String createProgressMessage(long transferred) { return MessageFormat.format(Messages.MONITOR_NAME_DOWNLOAD_TRANSFERRED_SIZE, FileUtils.byteCountToDisplaySize(transferred)); } private String createProgressMessage(long transferred, long total) { return MessageFormat.format(Messages.MONITOR_NAME_DOWNLOAD_TRANSFERRED_TOTAL_SIZE, FileUtils.byteCountToDisplaySize(transferred), FileUtils.byteCountToDisplaySize(total)); } private int calculateWorkUnitsForDownloadProgress(long newTransferred, long total) { double amount = (double) newTransferred / total; int workUnits = (int) (workUnitsPerDownloadTask * amount); return workUnits; } @Override public synchronized void downloadSucceeded(String path) { IProgressMonitor submonitor = downloads.get(path); finishMonitorWork(submonitor); submonitor.done(); downloadSucceeded = true; } @Override public synchronized void downloadFailed(String path) { IProgressMonitor submonitor = downloads.get(path); finishMonitorWork(submonitor); submonitor.done(); } private void finishMonitorWork(IProgressMonitor submonitor) { workUnfinishedTaskUnits(submonitor); if (workUnitsRemainder > 0) { workOneRemainderUnit(submonitor); } } private void workUnfinishedTaskUnits(IProgressMonitor submonitor) { int unfinishedWorkUnits = workUnitsPerDownloadTask - finishedWorkUnits; if (unfinishedWorkUnits > 0) { submonitor.worked(unfinishedWorkUnits); } } private void workOneRemainderUnit(IProgressMonitor monitor) { monitor.worked(1); workUnitsRemainder--; } public boolean isDownloadSucceeded() { return downloadSucceeded; } public void finish() { finishWorkForSkippedTasks(); finishWorkForRemainder(); } private void finishWorkForSkippedTasks() { int skippedDownloadTasks = maximumNumberOfDownloads - downloads.size(); for (int i = 0; i < skippedDownloadTasks; i++) { monitor.worked(workUnitsPerDownloadTask); } } private void finishWorkForRemainder() { if (workUnitsRemainder > 0) { monitor.worked(workUnitsRemainder); } } }