/******************************************************************************* * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org> * Copyright (C) 2012, Matthias Sohn <matthias.sohn@sap.com> * * 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 *******************************************************************************/ package org.eclipse.egit.ui.internal.history; import java.io.IOException; import java.text.MessageFormat; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.egit.ui.Activator; import org.eclipse.egit.ui.JobFamilies; import org.eclipse.egit.ui.UIPreferences; import org.eclipse.egit.ui.internal.UIText; import org.eclipse.egit.ui.internal.trace.GitTraceLocation; import org.eclipse.jgit.annotations.NonNull; import org.eclipse.jface.resource.ResourceManager; import org.eclipse.jgit.revwalk.RevFlag; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; class GenerateHistoryJob extends Job { private static final int BATCH_SIZE = 256; private final GitHistoryPage page; private final SWTCommitList loadedCommits; private int itemToLoad = 1; private RevCommit commitToLoad; private RevCommit commitToShow; private int lastUpdateCnt; private boolean trace; private final RevWalk walk; private RevFlag highlightFlag; private int forcedRedrawsAfterListIsCompleted = 0; GenerateHistoryJob(final GitHistoryPage ghp, Control control, @NonNull RevWalk walk, ResourceManager resources) { super(NLS.bind(UIText.HistoryPage_refreshJob, Activator.getDefault() .getRepositoryUtil().getRepositoryName( ghp.getInputInternal().getRepository()))); page = ghp; this.walk = walk; highlightFlag = walk.newFlag("highlight"); //$NON-NLS-1$ loadedCommits = new SWTCommitList(control, resources); loadedCommits.source(walk); trace = GitTraceLocation.HISTORYVIEW.isActive(); } @Override protected IStatus run(final IProgressMonitor monitor) { IStatus status = Status.OK_STATUS; int maxCommits = Activator.getDefault().getPreferenceStore() .getInt(UIPreferences.HISTORY_MAX_NUM_COMMITS); boolean incomplete = false; boolean commitNotFound = false; try { if (trace) GitTraceLocation.getTrace().traceEntry( GitTraceLocation.HISTORYVIEW.getLocation()); final boolean loadIncrementally = !Activator.getDefault() .getPreferenceStore() .getBoolean(UIPreferences.RESOURCEHISTORY_SHOW_FINDTOOLBAR); try { for (;;) { int oldsz = loadedCommits.size(); if (trace) GitTraceLocation.getTrace().trace( GitTraceLocation.HISTORYVIEW.getLocation(), "Filling commit list"); //$NON-NLS-1$ // ensure that filling (here) and reading (CommitGraphTable) // the commit list is thread safe synchronized (loadedCommits) { if (commitToLoad != null) { loadedCommits.fillTo(commitToLoad, maxCommits); commitToShow = commitToLoad; commitToLoad = null; boolean commitFound = false; for (RevCommit commit : loadedCommits) { if (commit.getId().equals(commitToShow.getId())) { commitFound = true; break; } } commitNotFound = !commitFound; } else { loadedCommits.fillTo(oldsz + BATCH_SIZE - 1); if (oldsz == loadedCommits.size()) { forcedRedrawsAfterListIsCompleted++; break; } } } if (monitor.isCanceled()) return Status.CANCEL_STATUS; if (loadedCommits.size() > itemToLoad + (BATCH_SIZE / 2) + 1 && loadIncrementally) break; if (maxCommits > 0 && loadedCommits.size() > maxCommits) { incomplete = true; break; } if (loadedCommits.size() != 1) monitor.setTaskName(MessageFormat .format(UIText.GenerateHistoryJob_taskFoundMultipleCommits, Integer.valueOf(loadedCommits.size()))); else monitor.setTaskName(UIText.GenerateHistoryJob_taskFoundSingleCommit); } } catch (IOException e) { status = new Status(IStatus.ERROR, Activator.getPluginId(), UIText.GenerateHistoryJob_errorComputingHistory, e); } if (trace) GitTraceLocation.getTrace().trace( GitTraceLocation.HISTORYVIEW.getLocation(), "Loaded " + loadedCommits.size() + " commits"); //$NON-NLS-1$ //$NON-NLS-2$ if (commitNotFound) { if (forcedRedrawsAfterListIsCompleted < 1 && !loadIncrementally) page.setWarningTextInUIThread(this); } else updateUI(incomplete); } finally { monitor.done(); if (trace) GitTraceLocation.getTrace().traceExit( GitTraceLocation.HISTORYVIEW.getLocation()); } return status; } private void updateUI(boolean incomplete) { if (trace) GitTraceLocation.getTrace().traceEntry( GitTraceLocation.HISTORYVIEW.getLocation()); try { if (!(forcedRedrawsAfterListIsCompleted == 1) && !incomplete && loadedCommits.size() == lastUpdateCnt) return; if (forcedRedrawsAfterListIsCompleted == 1) forcedRedrawsAfterListIsCompleted++; final SWTCommit[] asArray = new SWTCommit[loadedCommits.size()]; loadedCommits.toArray(asArray); page.showCommitList(this, loadedCommits, asArray, commitToShow, incomplete, highlightFlag); commitToShow = null; lastUpdateCnt = loadedCommits.size(); } finally { if (trace) GitTraceLocation.getTrace().traceExit( GitTraceLocation.HISTORYVIEW.getLocation()); } } void release() { if (getState() == Job.NONE) dispose(); else addJobChangeListener(new JobChangeAdapter() { @Override public void done(final IJobChangeEvent event) { dispose(); } }); } private void dispose() { walk.close(); Display.getDefault().asyncExec(new Runnable() { @Override public void run() { loadedCommits.dispose(); } }); } @Override public boolean belongsTo(Object family) { if (JobFamilies.GENERATE_HISTORY.equals(family)) return true; return super.belongsTo(family); } void setLoadHint(final int index) { itemToLoad = index; } void setLoadHint(final RevCommit c) { commitToLoad = c; } int loadMoreItemsThreshold() { return loadedCommits.size() - (BATCH_SIZE / 2); } }