Update org.apache.commons:commons-compress to 1.25.0
[egit/eclipse.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / reflog / ReflogViewContentProvider.java
blob1f0d28f8bbe188556ee4fa961ef95124d554ab4c
1 /*******************************************************************************
2 * Copyright (c) 2011, 2017 Chris Aniszczyk <caniszczyk@gmail.com> and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License 2.0
5 * which accompanies this distribution, and is available at
6 * https://www.eclipse.org/legal/epl-2.0/
8 * SPDX-License-Identifier: EPL-2.0
10 * Contributors:
11 * Chris Aniszczyk <caniszczyk@gmail.com> - initial implementation
12 * EclipseSource - Filtered Viewer
13 * Thomas Wolf <thomas.wolf@paranor.ch> - deferred loading
14 *******************************************************************************/
15 package org.eclipse.egit.ui.internal.reflog;
17 import java.io.File;
18 import java.io.IOException;
19 import java.util.Objects;
21 import org.eclipse.core.runtime.Assert;
22 import org.eclipse.core.runtime.IProgressMonitor;
23 import org.eclipse.core.runtime.jobs.IJobChangeEvent;
24 import org.eclipse.core.runtime.jobs.ISchedulingRule;
25 import org.eclipse.core.runtime.jobs.JobChangeAdapter;
26 import org.eclipse.egit.ui.Activator;
27 import org.eclipse.egit.ui.internal.UIText;
28 import org.eclipse.jface.viewers.AbstractTreeViewer;
29 import org.eclipse.jface.viewers.ITreeContentProvider;
30 import org.eclipse.jface.viewers.Viewer;
31 import org.eclipse.jgit.api.Git;
32 import org.eclipse.jgit.lib.Repository;
33 import org.eclipse.jgit.revwalk.RevWalk;
34 import org.eclipse.swt.widgets.Control;
35 import org.eclipse.ui.model.WorkbenchAdapter;
36 import org.eclipse.ui.progress.DeferredTreeContentManager;
37 import org.eclipse.ui.progress.IDeferredWorkbenchAdapter;
38 import org.eclipse.ui.progress.IElementCollector;
40 /**
41 * A content provider for reflog entries given a repository and a ref.
43 public class ReflogViewContentProvider implements ITreeContentProvider {
45 private DeferredTreeContentManager loader;
47 private Object currentInput;
49 /**
50 * Serializes concurrent attempts to load the reflog.
52 private static class ReflogSchedulingRule implements ISchedulingRule {
54 private final File gitDir;
56 public ReflogSchedulingRule(File gitDir) {
57 this.gitDir = gitDir;
60 @Override
61 public boolean contains(ISchedulingRule rule) {
62 if (rule instanceof ReflogSchedulingRule) {
63 return Objects.equals(gitDir,
64 ((ReflogSchedulingRule) rule).gitDir);
66 return false;
69 @Override
70 public boolean isConflicting(ISchedulingRule rule) {
71 return rule instanceof ReflogSchedulingRule;
76 private static final WorkbenchAdapter ERROR_ELEMENT = new WorkbenchAdapter() {
78 @Override
79 public String getLabel(Object object) {
80 return UIText.ReflogView_ErrorOnLoad;
85 /**
86 * Input class for this content provider.
88 public static class ReflogInput extends WorkbenchAdapter
89 implements IDeferredWorkbenchAdapter {
91 private final Repository repository;
93 private final String ref;
95 private final ISchedulingRule rule;
97 private ReflogItem[] refLog;
99 /**
100 * Create input with non-null repository and non-null ref
102 * @param repository
103 * @param ref
105 public ReflogInput(Repository repository, String ref) {
106 Assert.isNotNull(repository, "Repository cannot be null"); //$NON-NLS-1$
107 Assert.isNotNull(ref, "Ref cannot be null"); //$NON-NLS-1$
108 this.repository = repository;
109 this.ref = ref;
110 this.rule = new ReflogSchedulingRule(repository.getDirectory());
114 * Get repository
116 * @return repository
118 public Repository getRepository() {
119 return repository;
123 * Retrieves the ref.
125 * @return the ref
127 public String getRef() {
128 return ref;
131 @Override
132 public Object[] getChildren(Object o) {
133 if (refLog != null) {
134 return refLog;
136 return null;
139 @Override
140 public void fetchDeferredChildren(Object object,
141 IElementCollector collector, IProgressMonitor monitor) {
142 if (refLog != null) {
143 return; // Already loaded.
145 try (Git git = new Git(repository);
146 RevWalk walk = new RevWalk(repository)) {
147 refLog = git.reflog().setRef(ref).call().stream()
148 .map(entry -> {
149 String commitMessage = null;
150 try {
151 commitMessage = walk
152 .parseCommit(entry.getNewId())
153 .getShortMessage();
154 } catch (IOException e) {
155 // Ignore here
157 return new ReflogItem(ReflogInput.this, entry,
158 commitMessage);
160 .toArray(ReflogItem[]::new);
161 collector.add(refLog, monitor);
162 } catch (Exception e) {
163 Activator.logError("Error running reflog command", e); //$NON-NLS-1$
164 collector.add(ERROR_ELEMENT, monitor);
168 @Override
169 public boolean isContainer() {
170 return true;
173 @Override
174 public ISchedulingRule getRule(Object object) {
175 return rule;
179 @Override
180 public Object[] getElements(Object inputElement) {
181 return getChildren(inputElement);
184 @Override
185 public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
186 if (oldInput != null && loader != null) {
187 loader.cancel(oldInput);
189 currentInput = newInput;
190 if (viewer instanceof AbstractTreeViewer && newInput != null) {
191 loader = new DeferredBatchLoader((AbstractTreeViewer) viewer);
192 loader.addUpdateCompleteListener(new JobChangeAdapter() {
194 @Override
195 public void done(IJobChangeEvent event) {
196 if (event.getResult().isOK()) {
197 // Force a selection event
198 viewer.setSelection(viewer.getSelection());
205 @Override
206 public void dispose() {
207 if (currentInput != null && loader != null) {
208 loader.cancel(currentInput);
210 currentInput = null;
211 loader = null;
214 @Override
215 public Object[] getChildren(Object parentElement) {
216 if (parentElement instanceof ReflogInput && loader != null) {
217 Object[] knownChildren = ((ReflogInput) parentElement)
218 .getChildren(parentElement);
219 if (knownChildren != null) {
220 return knownChildren;
222 return loader.getChildren(parentElement);
224 return new Object[0];
227 @Override
228 public Object getParent(Object element) {
229 return null;
232 @Override
233 public boolean hasChildren(Object element) {
234 return false;
238 * A variant of {@link DeferredTreeContentManager} that doesn't use a
239 * separate UI job to fill in the tree. With UI jobs, it's simply impossible
240 * to know what has already been added when there are several loading jobs.
241 * For our use case (load the whole reflog, then add it to the tree) a
242 * {@link org.eclipse.swt.widgets.Display#syncExec(Runnable) syncExec()} is
243 * sufficient.
245 private static class DeferredBatchLoader
246 extends DeferredTreeContentManager {
248 private AbstractTreeViewer viewer;
250 public DeferredBatchLoader(AbstractTreeViewer viewer) {
251 super(viewer);
252 this.viewer = viewer;
256 * Add child nodes, removing the error element if appropriate. Contrary
257 * to the super implementation, this does <em>not</em> use a UI job but
258 * a simple {@link org.eclipse.swt.widgets.Display#syncExec(Runnable)
259 * syncExec()}.
261 * @param parent
262 * to add the {@code children} to
263 * @param children
264 * to add to the {@code parent}
265 * @param monitor
266 * is ignored
268 @Override
269 protected void addChildren(Object parent, Object[] children,
270 IProgressMonitor monitor) {
271 Control control = viewer.getControl();
272 if (control == null || control.isDisposed()) {
273 return;
275 control.getDisplay().syncExec(() -> {
276 if (!control.isDisposed()) {
277 try {
278 control.setRedraw(false);
279 if (children.length != 1
280 || children[0] != ERROR_ELEMENT) {
281 viewer.remove(ERROR_ELEMENT);
283 viewer.add(parent, children);
284 } finally {
285 control.setRedraw(true);