Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: fa972e92ff176a22e7f0155560d07c7707b601e4 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                                                                
                                                                              






                                                                        
                                    
                                                            


                                                                                 
                    
                         
 
                                       
                                                 
                                                     
                                                     
                                                      
                                     

                                                    
                                                      


                                        
                                       



                                                          

   
                                                                      
   

                                                                        



                                                  
           

































                                                                                      
 

                                                 
           

                                                                




                                                    

                                                   
                                            
 










                                                                                                
                                                                                        




                                 
                                     




                                                   








                                        


                                                       
                                              
                         
                                    
                 
 


                                                                                        


                                                          
                                                             



                                                                                                      
                                               
                                                                                                    
                                                                      

                         







                                                               
                                    





                                                          

         
                 
                                                                                   




                                                                               
                                                                                      









                                                                                           
                 

         
                 
                               




                                                             

         
                 
                                                           
                                                                             




                                                                              


                                                                 

         
                 



                                                 
                 

                                                    
         
















































                                                                                                   
 
/*******************************************************************************
 * Copyright (c) 2011, 2017 Chris Aniszczyk <caniszczyk@gmail.com> and others.
 * 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
 *
 * Contributors:
 *   Chris Aniszczyk <caniszczyk@gmail.com> - initial implementation
 *   EclipseSource - Filtered Viewer
 *   Thomas Wolf <thomas.wolf@paranor.ch> - deferred loading
 *******************************************************************************/
package org.eclipse.egit.ui.internal.reflog;

import java.io.File;
import java.util.Objects;

import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.egit.ui.Activator;
import org.eclipse.egit.ui.internal.UIText;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.model.WorkbenchAdapter;
import org.eclipse.ui.progress.DeferredTreeContentManager;
import org.eclipse.ui.progress.IDeferredWorkbenchAdapter;
import org.eclipse.ui.progress.IElementCollector;

/**
 * A content provider for reflog entries given a repository and a ref.
 */
public class ReflogViewContentProvider implements ITreeContentProvider {

	private DeferredTreeContentManager loader;

	private Object currentInput;

	/**
	 * Serializes concurrent attempts to load the reflog.
	 */
	private static class ReflogSchedulingRule implements ISchedulingRule {

		private final File gitDir;

		public ReflogSchedulingRule(File gitDir) {
			this.gitDir = gitDir;
		}

		@Override
		public boolean contains(ISchedulingRule rule) {
			if (rule instanceof ReflogSchedulingRule) {
				return Objects.equals(gitDir,
						((ReflogSchedulingRule) rule).gitDir);
			}
			return false;
		}

		@Override
		public boolean isConflicting(ISchedulingRule rule) {
			return rule instanceof ReflogSchedulingRule;
		}

	}

	private static final WorkbenchAdapter ERROR_ELEMENT = new WorkbenchAdapter() {

		@Override
		public String getLabel(Object object) {
			return UIText.ReflogView_ErrorOnLoad;
		}
	};


	/**
	 * Input class for this content provider.
	 */
	public static class ReflogInput extends WorkbenchAdapter
			implements IDeferredWorkbenchAdapter {

		private final Repository repository;

		private final String ref;

		private final ISchedulingRule rule;

		private ReflogItem[] refLog;

		/**
		 * Create input with non-null repository and non-null ref
		 *
		 * @param repository
		 * @param ref
		 */
		public ReflogInput(Repository repository, String ref) {
			Assert.isNotNull(repository, "Repository cannot be null"); //$NON-NLS-1$
			Assert.isNotNull(ref, "Ref cannot be null"); //$NON-NLS-1$
			this.repository = repository;
			this.ref = ref;
			this.rule = new ReflogSchedulingRule(repository.getDirectory());
		}

		/**
		 * Get repository
		 *
		 * @return repository
		 */
		public Repository getRepository() {
			return repository;
		}

		/**
		 * Retrieves the ref.
		 *
		 * @return the ref
		 */
		public String getRef() {
			return ref;
		}

		@Override
		public Object[] getChildren(Object o) {
			if (refLog != null) {
				return refLog;
			}
			return null;
		}

		@Override
		public void fetchDeferredChildren(Object object,
				IElementCollector collector, IProgressMonitor monitor) {
			if (refLog != null) {
				return; // Already loaded.
			}
			try (Git git = new Git(repository)) {
				refLog = git.reflog().setRef(ref).call().stream()
						.map(entry -> new ReflogItem(ReflogInput.this, entry))
						.toArray(ReflogItem[]::new);
				collector.add(refLog, monitor);
			} catch (Exception e) {
				Activator.logError("Error running reflog command", e); //$NON-NLS-1$
				collector.add(ERROR_ELEMENT, monitor);
			}
		}

		@Override
		public boolean isContainer() {
			return true;
		}

		@Override
		public ISchedulingRule getRule(Object object) {
			return rule;
		}
	}

	@Override
	public Object[] getElements(Object inputElement) {
		return getChildren(inputElement);
	}

	@Override
	public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		if (oldInput != null && loader != null) {
			loader.cancel(oldInput);
		}
		currentInput = newInput;
		if (viewer instanceof AbstractTreeViewer && newInput != null) {
			loader = new DeferredBatchLoader((AbstractTreeViewer) viewer);
			loader.addUpdateCompleteListener(new JobChangeAdapter() {

				@Override
				public void done(IJobChangeEvent event) {
					if (event.getResult().isOK()) {
						// Force a selection event
						viewer.setSelection(viewer.getSelection());
					}
				}
			});
		}
	}

	@Override
	public void dispose() {
		if (currentInput != null && loader != null) {
			loader.cancel(currentInput);
		}
		currentInput = null;
		loader = null;
	}

	@Override
	public Object[] getChildren(Object parentElement) {
		if (parentElement instanceof ReflogInput && loader != null) {
			Object[] knownChildren = ((ReflogInput) parentElement)
					.getChildren(parentElement);
			if (knownChildren != null) {
				return knownChildren;
			}
			return loader.getChildren(parentElement);
		}
		return new Object[0];
	}

	@Override
	public Object getParent(Object element) {
		return null;
	}

	@Override
	public boolean hasChildren(Object element) {
		return false;
	}

	/**
	 * A variant of {@link DeferredTreeContentManager} that doesn't use a
	 * separate UI job to fill in the tree. With UI jobs, it's simply impossible
	 * to know what has already been added when there are several loading jobs.
	 * For our use case (load the whole reflog, then add it to the tree) a
	 * {@link org.eclipse.swt.widgets.Display#syncExec(Runnable) syncExec()} is
	 * sufficient.
	 */
	private static class DeferredBatchLoader
			extends DeferredTreeContentManager {

		private AbstractTreeViewer viewer;

		public DeferredBatchLoader(AbstractTreeViewer viewer) {
			super(viewer);
			this.viewer = viewer;
		}

		/**
		 * Add child nodes, removing the error element if appropriate. Contrary
		 * to the super implementation, this does <em>not</em> use a UI job but
		 * a simple {@link org.eclipse.swt.widgets.Display#syncExec(Runnable)
		 * syncExec()}.
		 *
		 * @param parent
		 *            to add the {@code children} to
		 * @param children
		 *            to add to the {@code parent}
		 * @param monitor
		 *            is ignored
		 */
		@Override
		protected void addChildren(Object parent, Object[] children,
				IProgressMonitor monitor) {
			Control control = viewer.getControl();
			if (control == null || control.isDisposed()) {
				return;
			}
			control.getDisplay().syncExec(() -> {
				if (!control.isDisposed()) {
					if (children.length != 1 || children[0] != ERROR_ELEMENT) {
						viewer.remove(ERROR_ELEMENT);
					}
					viewer.add(parent, children);
				}
			});
		}
	}
}

Back to the top