tikhomirov@148: /*
tikhomirov@148:  * Copyright (c) 2011 TMate Software Ltd
tikhomirov@148:  *  
tikhomirov@148:  * This program is free software; you can redistribute it and/or modify
tikhomirov@148:  * it under the terms of the GNU General Public License as published by
tikhomirov@148:  * the Free Software Foundation; version 2 of the License.
tikhomirov@148:  *
tikhomirov@148:  * This program is distributed in the hope that it will be useful,
tikhomirov@148:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
tikhomirov@148:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
tikhomirov@148:  * GNU General Public License for more details.
tikhomirov@148:  *
tikhomirov@148:  * For information on how to redistribute this software under
tikhomirov@148:  * the terms of a license other than GNU General Public License
tikhomirov@148:  * contact TMate Software at support@hg4j.com
tikhomirov@148:  */
tikhomirov@148: package org.tmatesoft.hg.util;
tikhomirov@148: 
tikhomirov@148: /**
tikhomirov@148:  * Mix-in to report progress of a long-running operation
tikhomirov@148:  *  
tikhomirov@148:  * @author Artem Tikhomirov
tikhomirov@148:  * @author TMate Software Ltd.
tikhomirov@148:  */
tikhomirov@148: public interface ProgressSupport {
tikhomirov@148: 
tikhomirov@215: 	// -1 for unspecified?
tikhomirov@215: 	public void start(int totalUnits);
tikhomirov@148: 	public void worked(int units);
tikhomirov@215: 	// XXX have to specify whether PS implementors may expect #done regardless of job completion (i.e. in case of cancellation) 
tikhomirov@148: 	public void done();
tikhomirov@148: 
tikhomirov@148: 	static class Factory {
tikhomirov@148: 
tikhomirov@148: 		/**
tikhomirov@148: 		 * @param target object that might be capable to report progress. Can be null
tikhomirov@148: 		 * @return support object extracted from target or an empty, no-op implementation
tikhomirov@148: 		 */
tikhomirov@148: 		public static ProgressSupport get(Object target) {
tikhomirov@356: 			ProgressSupport ps = Adaptable.Factory.getAdapter(target, ProgressSupport.class, null);
tikhomirov@356: 			if (ps != null) {
tikhomirov@356: 				return ps;
tikhomirov@148: 			}
tikhomirov@148: 			return new ProgressSupport() {
tikhomirov@215: 				public void start(int totalUnits) {
tikhomirov@148: 				}
tikhomirov@148: 				public void worked(int units) {
tikhomirov@148: 				}
tikhomirov@148: 				public void done() {
tikhomirov@148: 				}
tikhomirov@148: 			};
tikhomirov@148: 		}
tikhomirov@148: 	}
tikhomirov@215: 	
tikhomirov@215: 	class Sub implements ProgressSupport {
tikhomirov@215: 		private final ProgressSupport ps;
tikhomirov@215: 		private int total;
tikhomirov@215: 		private int units;
tikhomirov@215: 		private int psUnits;
tikhomirov@215: 
tikhomirov@215: 		public Sub(ProgressSupport parent, int parentUnits) {
tikhomirov@215: 			if (parent == null) {
tikhomirov@215: 				throw new IllegalArgumentException();
tikhomirov@215: 			}
tikhomirov@215: 			ps = parent;
tikhomirov@215: 			psUnits = parentUnits;
tikhomirov@215: 		}
tikhomirov@215: 
tikhomirov@215: 		public void start(int totalUnits) {
tikhomirov@215: 			total = totalUnits;
tikhomirov@215: 		}
tikhomirov@215: 
tikhomirov@215: 		public void worked(int worked) {
tikhomirov@215: 			// FIXME fine-grained subprogress report. now only report at about 50% 
tikhomirov@215: 			if (psUnits > 1 && units < total/2 && units+worked > total/2) {
tikhomirov@215: 				ps.worked(psUnits/2);
tikhomirov@215: 				psUnits -= psUnits/2;
tikhomirov@215: 			}
tikhomirov@215: 			units += worked;
tikhomirov@215: 		}
tikhomirov@215: 
tikhomirov@215: 		public void done() {
tikhomirov@215: 			ps.worked(psUnits);
tikhomirov@215: 		}
tikhomirov@215: 	}
tikhomirov@215: 
tikhomirov@215: 	interface Target {
tikhomirov@215: 		T set(ProgressSupport ps);
tikhomirov@215: 	}
tikhomirov@148: }