blob: 1e84777f42420832a89159decd158a414b8fc421 [file] [log] [blame]
package org.eclipse.jdt.internal.core.builder.impl;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.internal.core.builder.*;
import org.eclipse.jdt.internal.core.Util;
import org.eclipse.jdt.internal.compiler.problem.AbortCompilation;
import java.text.NumberFormat;
import java.util.*;
/**
* A utility for notifying clients of changes during a build.
* This includes, progress, build events, etc.
*/
public class BuildNotifier {
protected JavaDevelopmentContextImpl fDC;
protected boolean fIsBatch;
protected IBuildMonitor fBuildMonitor;
protected IProgressMonitor fProgress;
protected boolean fCancelling = false;
protected float fPercentComplete;
protected float fProgressPerCompilationUnit;
protected Vector fBuildListeners;
protected int fNewErrorCount = 0;
protected int fFixedErrorCount = 0;
protected int fNewWarningCount = 0;
protected int fFixedWarningCount = 0;
protected int fWorkDone = 0;
protected int fTotalWork;
public static boolean DEBUG = false;
protected String previousSubtask;
public BuildNotifier(JavaDevelopmentContextImpl dc, boolean isBatch) {
fDC = dc;
fIsBatch = isBatch;
fProgress = dc.getProgressMonitor();
fBuildMonitor = dc.getBuildMonitor();
fBuildListeners = dc.getBuildListeners();
fTotalWork = 1000000;
}
public void begin() {
if (fBuildMonitor != null) {
fBuildMonitor.beginBuild(fIsBatch ? Util.bind("build.beginBatch") : Util.bind("build.beginIncremental")); //$NON-NLS-2$ //$NON-NLS-1$
}
if (fProgress != null) {
fProgress.beginTask("", fTotalWork); //$NON-NLS-1$
}
this.previousSubtask = null;
}
/**
* Check whether the build has been canceled.
*/
public void checkCancel() {
if (fProgress != null && fProgress.isCanceled()) {
throw new OperationCanceledException();
}
}
/**
* Check whether the build has been canceled.
* Must use this call instead of checkCancel() when within the compiler.
*/
public void checkCancelWithinCompiler() {
if (fProgress != null && fProgress.isCanceled() && !fCancelling) {
// Once the compiler has been canceled, don't check again.
setCancelling(true);
// Only AbortCompilation can stop the compiler cleanly.
// We check cancelation again following the call to compile.
throw new AbortCompilation(true, null);
}
}
/**
* Notification while within a compile that a unit has finished being compiled.
*/
public void compiled(CompilerCompilationUnit unit) {
compiling(unit);
}
/**
* Notification while within a compile that a unit is starting to be compiled.
*/
public void compiling(CompilerCompilationUnit unit) {
String message = new String(unit.getFileName());
message = message.replace('\\', '/');
// Trim off project names
int start = message.indexOf('/', 1);
int end = message.lastIndexOf('/');
if (end <= start){
message = Util.bind("build.compiling", message.substring(start+1)); //$NON-NLS-1$
} else {
message = Util.bind("build.compilingContent", message.substring(start+1, end)); //$NON-NLS-1$
}
subTask(message);
updateProgressDelta(fProgressPerCompilationUnit/2);
checkCancelWithinCompiler();
}
public void done() {
updateProgress(1.0f);
subTask(Util.bind("build.done")); //$NON-NLS-1$
if (fProgress != null) {
fProgress.done();
}
if (fBuildMonitor != null) {
fBuildMonitor.endBuild(fIsBatch ? Util.bind("build.endBatch") : Util.bind("build.endIncremental")); //$NON-NLS-2$ //$NON-NLS-1$
}
this.previousSubtask = null;
}
/**
* Notify listeners that elements have changed.
*/
public void notifyElementsChanged(ConvertedCompilationResult[] results, StateImpl oldState, StateImpl newState) {
// if (fBuildListeners.size() == 0) {
// return;
// }
for (int i = 0; i < results.length; ++i) {
ConvertedCompilationResult result = results[i];
PackageElement element = result.getPackageElement();
/* notify the build monitor */
if (fBuildMonitor != null) {
String typeName = element.getFileName();
int lastDot = typeName.lastIndexOf('.');
typeName = typeName.substring(0, lastDot);
fBuildMonitor.compiled(element.getPackage().getName() + '.' + typeName);
}
Vector oldProblems = null;
Vector newProblems = null;
if (oldState != null) {
SourceEntry oldEntry = oldState.getSourceEntry(element);
if (oldEntry != null) {
oldProblems = oldState.getProblemReporter().getProblemVector(oldEntry);
}
}
SourceEntry newEntry = newState.getSourceEntry(element);
if (newEntry != null) {
newProblems = newState.getProblemReporter().getProblemVector(newEntry);
}
updateProblemCounts(oldProblems, newProblems);
ISourceFragment fragment = (newEntry == null ? null : new SourceFragmentImpl(newEntry));
BuildEvent event = new BuildEvent(fragment, fNewErrorCount, fFixedErrorCount, fNewWarningCount, fFixedWarningCount);
for (int j = 0, size = fBuildListeners.size(); j < size; ++j) {
((IBuildListener) fBuildListeners.elementAt(j)).buildUpdate(event);
}
}
}
/**
* Returns a string describing the problems.
*/
protected String problemsMessage() {
int numNew = fNewErrorCount + fNewWarningCount;
int numFixed = fFixedErrorCount + fFixedWarningCount;
if (numNew == 0 && numFixed == 0) {
return ""; //$NON-NLS-1$
}
if (numFixed == 0) {
return '(' + numNew == 1 ? Util.bind("build.oneProblemFound", String.valueOf(numNew)) : Util.bind("build.problemsFound", String.valueOf(numNew)) +')'; //$NON-NLS-2$ //$NON-NLS-1$
} else
if (numNew == 0) {
return '(' + numFixed == 1 ? Util.bind("build.oneProblemFixed", String.valueOf(numFixed)) : Util.bind("build.problemsFixed", String.valueOf(numFixed)) + ')'; //$NON-NLS-2$ //$NON-NLS-1$
} else {
return '(' + (numFixed == 1 ? Util.bind("build.oneProblemFixed", String.valueOf(numFixed)) : Util.bind("build.problemsFixed", String.valueOf(numFixed))) //$NON-NLS-2$ //$NON-NLS-1$
+ (numNew == 1 ? Util.bind("build.oneProblemFound", String.valueOf(numNew)) : Util.bind("build.problemsFound", String.valueOf(numNew))) + ')'; //$NON-NLS-2$ //$NON-NLS-1$
}
}
/**
* Sets the cancelling flag, which indicates we are in the middle
* of being cancelled. Certain places (those callable indirectly from the compiler)
* should not check cancel again while this is true, to avoid OperationCanceledException
* being thrown at an inopportune time.
*/
public void setCancelling(boolean cancelling) {
fCancelling = cancelling;
}
/**
* Sets the amount of progress to report for compiling each compilation unit.
*/
public void setProgressPerCompilationUnit(float progress) {
fProgressPerCompilationUnit = progress;
}
public void subTask(String message) {
String pm = problemsMessage();
String msg = pm.length() == 0 ? message : pm + " " + message; //$NON-NLS-1$
if (msg.equals(this.previousSubtask)) return; // avoid refreshing with same one
if (DEBUG) System.out.println(msg);
if (fProgress != null) fProgress.subTask(msg);
this.previousSubtask = msg;
}
/**
* Update the problem counts given the old and new problems,
* either of which may be null.
*/
protected void updateProblemCounts(Vector oldProblems, Vector newProblems) {
if (oldProblems != null) {
for (int i = 0, oldSize = oldProblems.size(); i < oldSize; ++i) {
ProblemDetailImpl oldProblem = (ProblemDetailImpl) oldProblems.elementAt(i);
ProblemDetailImpl newProblem = null;
if (newProblems != null) {
for (int j = 0, newSize = newProblems.size(); j < newSize; ++j) {
ProblemDetailImpl pb = (ProblemDetailImpl) newProblems.elementAt(j);
if (oldProblem.equals(pb, true)) {
newProblem = pb;
break;
}
}
}
if (newProblem == null) {
if ((oldProblem.getSeverity() & IProblemDetail.S_ERROR) != 0) {
fFixedErrorCount++;
} else {
fFixedWarningCount++;
}
}
}
}
if (newProblems != null) {
for (int i = 0, newSize = newProblems.size(); i < newSize; ++i) {
ProblemDetailImpl newProblem = (ProblemDetailImpl) newProblems.elementAt(i);
ProblemDetailImpl oldProblem = null;
if (oldProblems != null) {
for (int j = 0, oldSize = oldProblems.size(); j < oldSize; ++j) {
ProblemDetailImpl pb = (ProblemDetailImpl) oldProblems.elementAt(j);
if (newProblem.equals(pb, true)) {
oldProblem = pb;
break;
}
}
}
if (oldProblem == null) {
if ((newProblem.getSeverity() & IProblemDetail.S_ERROR) != 0) {
fNewErrorCount++;
} else {
fNewWarningCount++;
}
}
}
}
}
public void updateProgress(float percentComplete) {
if (percentComplete > fPercentComplete) {
fPercentComplete = Math.min(percentComplete, 1.0f);
int work = Math.round(fPercentComplete * fTotalWork);
if (work > fWorkDone) {
if (fProgress != null) {
fProgress.worked(work - fWorkDone);
}
if (DEBUG) {
System.out.println(NumberFormat.getPercentInstance().format(fPercentComplete));
}
fWorkDone = work;
}
}
}
public void updateProgressDelta(float percentWorked) {
updateProgress(fPercentComplete + percentWorked);
}
}