/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG and others.
* 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:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.example.client.communication;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.riena.communication.core.progressmonitor.AbstractRemoteProgressMonitor;
import org.eclipse.riena.communication.core.progressmonitor.IRemoteProgressMonitor;
import org.eclipse.riena.communication.core.progressmonitor.RemoteProgressMonitorEvent;
import org.eclipse.riena.navigation.ApplicationNodeManager;
import org.eclipse.riena.navigation.ISubApplicationNode;
import org.eclipse.riena.navigation.model.ApplicationNode;
import org.eclipse.riena.navigation.ui.application.ProgressVisualizerLocator;
import org.eclipse.riena.ui.core.uiprocess.ProcessInfo;
import org.eclipse.riena.ui.core.uiprocess.UICallbackDispatcher;
import org.eclipse.riena.ui.core.uiprocess.UISynchronizer;
import org.eclipse.riena.ui.ridgets.IUIProcessRidget;
/**
* An {@link IRemoteProgressMonitor} visualizing progress inside an
* {@link IUIProcessRidget}
*/
public class ServiceProgressVisualizer extends AbstractRemoteProgressMonitor {
private final static double NORMALIZED_TOTAL_WORK = 10000;
// the monitor for delegation
private IProgressMonitor progressMonitor;
//name of the task working on
private String taskName;
private final Map<CommunicationDirection, CommunicationChannel> channels = new HashMap<CommunicationDirection, CommunicationChannel>();
enum CommunicationDirection {
REQUEST, RESPONSE;
}
/**
* describes the progress and total work of a {@link CommunicationDirection}
*/
private static class CommunicationChannel {
private int actualTotalWork = 0;
private int actualWorkedUnits = 0;
int getActualTotalWork() {
return actualTotalWork;
}
void setActualTotalWork(final int actualTotalWork) {
this.actualTotalWork = actualTotalWork;
}
int getActualWorkedUnits() {
return actualWorkedUnits;
}
void setActualWorkedUnits(final int actualWorkedUnits) {
this.actualWorkedUnits = actualWorkedUnits;
}
void workUnitsDone(final int bytes) {
setActualWorkedUnits(getActualWorkedUnits() + bytes);
}
/*
* normalize means recalculate the actual work as part of
* "total work for direction" which is the half of total work
*/
int normalizeActualWorkedUnits() {
if (actualWorkedUnits == 0) {
return 0;
}
final double workMultiplier = Double.valueOf(actualWorkedUnits) / Double.valueOf(actualTotalWork);
return (int) ((NORMALIZED_TOTAL_WORK / 2) * workMultiplier);
}
}
public ServiceProgressVisualizer(final String taskname, final IProgressMonitor progressMonitor) {
init(taskname, progressMonitor);
}
public ServiceProgressVisualizer(final String taskname) {
// ui stuff goes here
final UICallbackDispatcher callBackDispatcher = new UICallbackDispatcher(UISynchronizer.createSynchronizer());
final ISubApplicationNode subApplicationNode = locateActiveSubApplicationNode();
// init delegation
callBackDispatcher.addUIMonitor(new ProgressVisualizerLocator().getProgressVisualizer(subApplicationNode));
progressMonitor = callBackDispatcher.createThreadSwitcher();
init(taskname, progressMonitor);
configureProcessInfo(callBackDispatcher, subApplicationNode);
}
private void init(final String taskname, final IProgressMonitor progressMonitor) {
initChannels();
this.taskName = taskname;
this.progressMonitor = progressMonitor;
}
private void initChannels() {
// we can write and read ..
channels.put(CommunicationDirection.REQUEST, new CommunicationChannel());
channels.put(CommunicationDirection.RESPONSE, new CommunicationChannel());
}
private void configureProcessInfo(final UICallbackDispatcher callBackDispatcher,
final ISubApplicationNode applicationNode) {
final ProcessInfo processInfo = callBackDispatcher.getProcessInfo();
processInfo.setNote(taskName);
processInfo.setTitle(taskName);
processInfo.setDialogVisible(true);
processInfo.setContext(applicationNode);
processInfo.addPropertyChangeListener(new RemoteServiceCancelListener());
}
protected ISubApplicationNode locateActiveSubApplicationNode() {
final ApplicationNode applicationNode = (ApplicationNode) ApplicationNodeManager.getApplicationNode();
for (final ISubApplicationNode child : applicationNode.getChildren()) {
if (child.isActivated()) {
return child;
}
}
return null;
}
private static class RemoteServiceCancelListener implements PropertyChangeListener {
public void propertyChange(final PropertyChangeEvent evt) {
if (ProcessInfo.PROPERTY_CANCELED.equals(evt.getPropertyName())) {
//TODO which is the best way to handle that?
}
}
}
//
/// implement needed callbacks
@Override
public void start() {
super.start();
progressMonitor.beginTask(taskName, (int) NORMALIZED_TOTAL_WORK);
}
CommunicationChannel getChannel(final CommunicationDirection communicationDrection) {
return channels.get(communicationDrection);
}
@Override
public void request(final int bytes, final int totalBytes) {
workUntisCompleted(bytes, totalBytes, getChannel(CommunicationDirection.REQUEST));
}
public void request(final RemoteProgressMonitorEvent event) {
request(event.getBytesProcessed(), event.getTotalBytes());
}
@Override
public void response(final int bytes, final int totalBytes) {
workUntisCompleted(bytes, totalBytes, getChannel(CommunicationDirection.RESPONSE));
}
public void response(final RemoteProgressMonitorEvent event) {
response(event.getBytesProcessed(), event.getTotalBytes());
}
private void workUntisCompleted(final int bytes, final int totalBytes,
final CommunicationChannel communicationChannel) {
communicationChannel.actualTotalWork = totalBytes;
updateWorked(bytes, communicationChannel);
if (transferComplete()) {
progressMonitor.done();
return;
}
progressMonitor.worked(calculateTotalNormalizedProgress());
}
/*
* are we done?
*/
private boolean transferComplete() {
return calculateTotalNormalizedProgress() >= NORMALIZED_TOTAL_WORK;
}
private int calculateTotalNormalizedProgress() {
int sum = 0;
for (final CommunicationChannel channel : channels.values()) {
sum += channel.normalizeActualWorkedUnits();
}
return sum;
}
/*
* update the channel
*/
private void updateWorked(final int bytes, final CommunicationChannel communicationChannel) {
communicationChannel.workUnitsDone(bytes);
}
}