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"/*nonNLS*/) : Util.bind("build.beginIncremental"/*nonNLS*/)); | |
} | |
if (fProgress != null) { | |
fProgress.beginTask(""/*nonNLS*/, fTotalWork); | |
} | |
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"/*nonNLS*/, message.substring(start+1)); | |
} else { | |
message = Util.bind("build.compilingContent"/*nonNLS*/, message.substring(start+1, end)); | |
} | |
subTask(message); | |
updateProgressDelta(fProgressPerCompilationUnit/2); | |
checkCancelWithinCompiler(); | |
} | |
public void done() { | |
updateProgress(1.0f); | |
subTask(Util.bind("build.done"/*nonNLS*/)); | |
if (fProgress != null) { | |
fProgress.done(); | |
} | |
if (fBuildMonitor != null) { | |
fBuildMonitor.endBuild(fIsBatch ? Util.bind("build.endBatch"/*nonNLS*/) : Util.bind("build.endIncremental"/*nonNLS*/)); | |
} | |
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 ""/*nonNLS*/; | |
} | |
if (numFixed == 0) { | |
return '(' + numNew == 1 ? Util.bind("build.oneProblemFound"/*nonNLS*/, String.valueOf(numNew)) : Util.bind("build.problemsFound"/*nonNLS*/, String.valueOf(numNew)) +')'; | |
} else | |
if (numNew == 0) { | |
return '(' + numFixed == 1 ? Util.bind("build.oneProblemFixed"/*nonNLS*/, String.valueOf(numFixed)) : Util.bind("build.problemsFixed"/*nonNLS*/, String.valueOf(numFixed)) + ')'; | |
} else { | |
return '(' + (numFixed == 1 ? Util.bind("build.oneProblemFixed"/*nonNLS*/, String.valueOf(numFixed)) : Util.bind("build.problemsFixed"/*nonNLS*/, String.valueOf(numFixed))) | |
+ (numNew == 1 ? Util.bind("build.oneProblemFound"/*nonNLS*/, String.valueOf(numNew)) : Util.bind("build.problemsFound"/*nonNLS*/, String.valueOf(numNew))) + ')'; | |
} | |
} | |
/** | |
* 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 + " "/*nonNLS*/ + message; | |
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); | |
} | |
} |