aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBernard Leach2011-05-03 18:59:46 (EDT)
committerChris Aniszczyk2011-05-12 14:07:46 (EDT)
commit562ff7890f47f4be0cb9b6e76f8fc4d645374228 (patch)
treeb86fb8f538d58ed5561da75d443e8248e4607f00
parent2f724143881b110bff53983df9ccf1d88366acc1 (diff)
downloadegit-562ff7890f47f4be0cb9b6e76f8fc4d645374228.zip
egit-562ff7890f47f4be0cb9b6e76f8fc4d645374228.tar.gz
egit-562ff7890f47f4be0cb9b6e76f8fc4d645374228.tar.bz2
Add a 'Staging' viewrefs/changes/06/3106/10
Git's staging area is one of its most powerful features. This view provides users with the ability to drag-and-drop files between the working directory and index. Such an operation would be synonymous to adding the modified files to the index and tracking the untracked files. Other operations like committing is also possible from the view's context menu. Change-Id: I7d78aff4db32d864ac0410a178bad149c45b6440 CQ: 5115 Bug: 313263 Also-by: Remy Suen <remysuen@ca.ibm.com> Also-by: Matthias Sohn <matthias.sohn@sap.com> Signed-off-by: Chris Aniszczyk <caniszczyk@gmail.com>
-rw-r--r--org.eclipse.egit.ui/plugin.properties1
-rw-r--r--org.eclipse.egit.ui/plugin.xml17
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java26
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntry.java118
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntryAdapterFactory.java20
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java495
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingViewContentProvider.java77
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingViewLabelProvider.java100
-rw-r--r--org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties10
9 files changed, 864 insertions, 0 deletions
diff --git a/org.eclipse.egit.ui/plugin.properties b/org.eclipse.egit.ui/plugin.properties
index 77206c4..7007e8e 100644
--- a/org.eclipse.egit.ui/plugin.properties
+++ b/org.eclipse.egit.ui/plugin.properties
@@ -97,6 +97,7 @@ ShareProjectCommand_desc=Share the project using Git
ShareProjectCommandParameter_name = Project
GitRepositoriesView_name = Git Repositories
+GitStagingView_name = Git Staging
GitCategory_name = Git
GitRepositoryPerspective_name = Git Repository Exploring
Synchronize_Name=Git
diff --git a/org.eclipse.egit.ui/plugin.xml b/org.eclipse.egit.ui/plugin.xml
index f750c6d..e29489f 100644
--- a/org.eclipse.egit.ui/plugin.xml
+++ b/org.eclipse.egit.ui/plugin.xml
@@ -1146,6 +1146,13 @@
name="%GitRepositoriesView_name"
restorable="true">
</view>
+ <view
+ category="org.eclipse.egit.ui.GitCategory"
+ class="org.eclipse.egit.ui.internal.staging.StagingView"
+ icon="icons/eview16/repo_rep.gif"
+ id="org.eclipse.egit.ui.StagingView"
+ name="%GitStagingView_name">
+ </view>
<category
id="org.eclipse.egit.ui.GitCategory"
name="%GitCategory_name">
@@ -3546,4 +3553,14 @@
id="org.eclipse.egit.ui.internal.commit.CommitEditorInputFactory">
</factory>
</extension>
+ <extension
+ point="org.eclipse.core.runtime.adapters">
+ <factory
+ adaptableType="org.eclipse.egit.ui.internal.staging.StagingEntry"
+ class="org.eclipse.egit.ui.internal.staging.StagingEntryAdapterFactory">
+ <adapter
+ type="org.eclipse.core.resources.IResource">
+ </adapter>
+ </factory>
+ </extension>
</plugin>
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
index 83ad842..482e40f 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/UIText.java
@@ -3530,6 +3530,32 @@ public class UIText extends NLS {
public static String DecoratableResourceHelper_noHead;
/** */
+ public static String StagingView_UnstagedChanges;
+
+ /** */
+ public static String StagingView_StagedChanges;
+
+ /** */
+ public static String StagingView_CommitMessage;
+
+ /** */
+ public static String StagingView_Committer;
+
+ /** */
+ public static String StagingView_Author;
+
+ /** */
+ public static String StagingView_Ammend_Previous_Commit;
+
+ /** */
+ public static String StagingView_Add_Signed_Off_By;
+
+ /** */
+ public static String StagingView_Add_Change_ID;
+
+ /** */
+ public static String StagingView_Commit;
+
static {
initializeMessages(BUNDLE_NAME, UIText.class);
}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntry.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntry.java
new file mode 100644
index 0000000..2e9b414
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntry.java
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Bernard Leach <leachbj@bouncycastle.org>
+ *
+ * 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.staging;
+
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.egit.core.IteratorService;
+import org.eclipse.jgit.lib.Repository;
+
+
+/**
+ * A staged/unstaged entry in the table
+ */
+public class StagingEntry implements IAdaptable {
+ /**
+ * State of the node
+ */
+ public static enum State {
+ /** added to the index, not in the tree */
+ ADDED,
+ /** changed from tree to index */
+ CHANGED,
+ /** removed from index, but in tree */
+ REMOVED,
+ /** in index, but not filesystem */
+ MISSING,
+ /** modified on disk relative to the index */
+ MODIFIED,
+ /** partially staged, modified in workspace and in index */
+ PARTIALLY_MODIFIED,
+ /** not ignored, and not in the index */
+ UNTRACKED,
+ /** in conflict */
+ CONFLICTING;
+ }
+
+ private Repository repository;
+
+ private State state;
+
+ private String path;
+
+ /**
+ *
+ * @param repository TODO
+ * @param modified
+ * @param file
+ */
+ public StagingEntry(Repository repository, State modified, String file) {
+ this.repository = repository;
+ this.state = modified;
+ this.path = file;
+ }
+
+ /**
+ * @return the full path for this node
+ */
+ public String getPath() {
+ return path;
+ }
+
+ /**
+ * @return the state for this node
+ */
+ public State getState() {
+ return state;
+ }
+
+ public Object getAdapter(Class adapter) {
+ if (adapter == IResource.class) {
+ IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
+
+ IContainer findContainer = IteratorService.findContainer(root, repository.getWorkTree());
+ if (findContainer != null) {
+ IResource findMember = findContainer.findMember(path);
+ return findMember;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((path == null) ? 0 : path.hashCode());
+ result = prime * result + ((state == null) ? 0 : state.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ StagingEntry other = (StagingEntry) obj;
+ if (path == null) {
+ if (other.path != null)
+ return false;
+ } else if (!path.equals(other.path))
+ return false;
+ if (state != other.state)
+ return false;
+ return true;
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntryAdapterFactory.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntryAdapterFactory.java
new file mode 100644
index 0000000..b5e325e
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingEntryAdapterFactory.java
@@ -0,0 +1,20 @@
+package org.eclipse.egit.ui.internal.staging;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdapterFactory;
+
+/**
+ * An adapter factory for <code>StagingEntry</code>s so that the property page
+ * handler can open property pages on them correctly.
+ */
+public class StagingEntryAdapterFactory implements IAdapterFactory {
+
+ public Object getAdapter(Object adaptableObject, Class adapterType) {
+ return ((StagingEntry)adaptableObject).getAdapter(IResource.class);
+ }
+
+ public Class[] getAdapterList() {
+ return new Class[] { IResource.class };
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
new file mode 100644
index 0000000..fee079f
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingView.java
@@ -0,0 +1,495 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Bernard Leach <leachbj@bouncycastle.org>
+ *
+ * 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.staging;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.NotEnabledException;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.commands.ParameterizedCommand;
+import org.eclipse.core.commands.common.NotDefinedException;
+import org.eclipse.core.expressions.EvaluationContext;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.egit.core.project.RepositoryMapping;
+import org.eclipse.egit.ui.Activator;
+import org.eclipse.egit.ui.UIText;
+import org.eclipse.egit.ui.internal.dialogs.SpellcheckableMessageArea;
+import org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.layout.TableColumnLayout;
+import org.eclipse.jface.util.LocalSelectionTransfer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jgit.events.IndexChangedEvent;
+import org.eclipse.jgit.events.IndexChangedListener;
+import org.eclipse.jgit.events.ListenerHandle;
+import org.eclipse.jgit.events.RefsChangedEvent;
+import org.eclipse.jgit.events.RefsChangedListener;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.IndexDiff;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryState;
+import org.eclipse.jgit.lib.UserConfig;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.treewalk.FileTreeIterator;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DragSourceAdapter;
+import org.eclipse.swt.dnd.DragSourceEvent;
+import org.eclipse.swt.dnd.DropTargetAdapter;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.dnd.Transfer;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.ISelectionListener;
+import org.eclipse.ui.ISelectionService;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.handlers.IHandlerService;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * A GitX style staging view with embedded commit dialog.
+ */
+public class StagingView extends ViewPart {
+ private Label repositoryLabel;
+ private TableViewer stagedTableViewer;
+ private TableViewer unstagedTableViewer;
+ private SpellcheckableMessageArea commitMessageText;
+ private Text committerText;
+ private Text authorText;
+ private Button commitButton;
+
+ private boolean reactOnSelection = true;
+
+ private final List<ListenerHandle> myListeners = new LinkedList<ListenerHandle>();
+ private ISelectionListener selectionChangedListener;
+ private Repository currentRepository;
+
+ private final RefsChangedListener myRefsChangedListener = new RefsChangedListener() {
+ public void onRefsChanged(RefsChangedEvent event) {
+ // refs change when files are committed, we naturally want to remove
+ // committed files from the view
+ reload(event.getRepository());
+ }
+ };
+
+ private final IndexChangedListener myIndexChangedListener = new IndexChangedListener() {
+ public void onIndexChanged(IndexChangedEvent event) {
+ reload(event.getRepository());
+ }
+ };
+
+ @Override
+ public void createPartControl(Composite parent) {
+ parent.setLayout(new GridLayout(1, false));
+
+ repositoryLabel = new Label(parent, SWT.NONE);
+ repositoryLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ SashForm horizontalSashForm = new SashForm(parent, SWT.NONE);
+ horizontalSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+
+ Composite leftHandComposite = new Composite(horizontalSashForm, SWT.NONE);
+ leftHandComposite.setLayout(new GridLayout(1, false));
+
+ SashForm veriticalSashForm = new SashForm(leftHandComposite, SWT.VERTICAL);
+ veriticalSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+
+ Composite unstagedComposite = new Composite(veriticalSashForm, SWT.NONE);
+ unstagedComposite.setLayout(new GridLayout(1, false));
+
+ new Label(unstagedComposite, SWT.NONE).setText(UIText.StagingView_UnstagedChanges);
+
+ Composite unstagedTableComposite = new Composite(unstagedComposite, SWT.NONE);
+ unstagedTableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ unstagedTableComposite.setLayout(new TableColumnLayout());
+
+ unstagedTableViewer = new TableViewer(unstagedTableComposite, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI);
+ unstagedTableViewer.getTable().setLinesVisible(true);
+ unstagedTableViewer.setLabelProvider(new StagingViewLabelProvider());
+ unstagedTableViewer.setContentProvider(new StagingViewContentProvider(true));
+ unstagedTableViewer.addDragSupport(DND.DROP_MOVE,
+ new Transfer[] { LocalSelectionTransfer.getTransfer() },
+ new DragSourceAdapter() {
+ public void dragStart(DragSourceEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) stagedTableViewer
+ .getSelection();
+ event.doit = !selection.isEmpty();
+ }
+ });
+ unstagedTableViewer.addDropSupport(DND.DROP_MOVE,
+ new Transfer[] { LocalSelectionTransfer.getTransfer() },
+ new DropTargetAdapter() {
+ public void drop(DropTargetEvent event) {
+ final IStructuredSelection selection = (IStructuredSelection) stagedTableViewer
+ .getSelection();
+ unstage(selection);
+ }
+
+ public void dragOver(DropTargetEvent event) {
+ event.detail = DND.DROP_MOVE;
+ }
+ });
+
+ Composite commitMessageComposite = new Composite(horizontalSashForm, SWT.NONE);
+ commitMessageComposite.setLayout(new GridLayout(2, false));
+
+ Label commitMessageLabel = new Label(commitMessageComposite, SWT.NONE);
+ commitMessageLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+ commitMessageLabel.setText(UIText.StagingView_CommitMessage);
+
+ commitMessageText = new SpellcheckableMessageArea(commitMessageComposite, ""); //$NON-NLS-1$
+ commitMessageText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
+
+ Composite composite = new Composite(commitMessageComposite, SWT.NONE);
+ composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 2, 1));
+ composite.setLayout(new GridLayout(2, false));
+
+ new Label(composite, SWT.NONE).setText(UIText.StagingView_Committer);
+
+ committerText = new Text(composite, SWT.BORDER);
+ committerText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ new Label(composite, SWT.NONE).setText(UIText.StagingView_Author);
+
+ authorText = new Text(composite, SWT.BORDER);
+ authorText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ Button amendPreviousCommitButton = new Button(commitMessageComposite, SWT.CHECK);
+ amendPreviousCommitButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+ amendPreviousCommitButton.setText(UIText.StagingView_Ammend_Previous_Commit);
+
+ Button signedOffByButton = new Button(commitMessageComposite, SWT.CHECK);
+ signedOffByButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1));
+ signedOffByButton.setText(UIText.StagingView_Add_Signed_Off_By);
+
+ Button addChangeIdButton = new Button(commitMessageComposite, SWT.CHECK);
+ GridData addChangeIdButtonGridData = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
+ addChangeIdButtonGridData.minimumHeight = 1;
+ addChangeIdButton.setLayoutData(addChangeIdButtonGridData);
+ addChangeIdButton.setText(UIText.StagingView_Add_Change_ID);
+
+ commitButton = new Button(commitMessageComposite, SWT.NONE);
+ commitButton.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1));
+ commitButton.setText(UIText.StagingView_Commit);
+
+ Composite stagedComposite = new Composite(veriticalSashForm, SWT.NONE);
+ stagedComposite.setLayout(new GridLayout(1, false));
+
+ new Label(stagedComposite, SWT.NONE).setText(UIText.StagingView_StagedChanges);
+
+ Composite stagedTableComposite = new Composite(stagedComposite, SWT.NONE);
+ stagedTableComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
+ stagedTableComposite.setLayout(new TableColumnLayout());
+
+ stagedTableViewer = new TableViewer(stagedTableComposite, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI);
+ stagedTableViewer.getTable().setLinesVisible(true);
+ stagedTableViewer.setLabelProvider(new StagingViewLabelProvider());
+ stagedTableViewer.setContentProvider(new StagingViewContentProvider(false));
+ stagedTableViewer.addDragSupport(DND.DROP_MOVE,
+ new Transfer[] { LocalSelectionTransfer.getTransfer() },
+ new DragSourceAdapter() {
+ public void dragStart(DragSourceEvent event) {
+ IStructuredSelection selection = (IStructuredSelection) unstagedTableViewer
+ .getSelection();
+ event.doit = !selection.isEmpty();
+ }
+ });
+ stagedTableViewer.addDropSupport(DND.DROP_MOVE,
+ new Transfer[] { LocalSelectionTransfer.getTransfer() },
+ new DropTargetAdapter() {
+ public void drop(DropTargetEvent event) {
+ final IStructuredSelection selection = (IStructuredSelection) unstagedTableViewer
+ .getSelection();
+ stage(selection);
+ }
+
+ public void dragOver(DropTargetEvent event) {
+ event.detail = DND.DROP_MOVE;
+ }
+ });
+
+ selectionChangedListener = new ISelectionListener() {
+ public void selectionChanged(IWorkbenchPart part,
+ ISelection selection) {
+ if (!reactOnSelection)
+ return;
+
+ // this may happen if we switch between editors
+ if (part instanceof IEditorPart) {
+ IEditorInput input = ((IEditorPart) part).getEditorInput();
+ if (input instanceof IFileEditorInput)
+ reactOnSelection(new StructuredSelection(
+ ((IFileEditorInput) input).getFile()));
+ } else
+ reactOnSelection(selection);
+ }
+ };
+
+ horizontalSashForm.setWeights(new int[] {40, 60});
+ veriticalSashForm.setWeights(new int[] {50, 50});
+
+ // react on selection changes
+ ISelectionService srv = (ISelectionService) getSite().getService(
+ ISelectionService.class);
+ srv.addPostSelectionListener(selectionChangedListener);
+
+ getSite().setSelectionProvider(unstagedTableViewer);
+ }
+
+ private void reactOnSelection(ISelection selection) {
+ if (selection instanceof StructuredSelection) {
+ StructuredSelection ssel = (StructuredSelection) selection;
+ if (ssel.size() != 1)
+ return;
+ if (ssel.getFirstElement() instanceof IResource)
+ showResource((IResource) ssel.getFirstElement());
+ if (ssel.getFirstElement() instanceof IAdaptable) {
+ IResource adapted = (IResource) ((IAdaptable) ssel
+ .getFirstElement()).getAdapter(IResource.class);
+ if (adapted != null)
+ showResource(adapted);
+ } else if (ssel.getFirstElement() instanceof RepositoryTreeNode) {
+ RepositoryTreeNode repoNode = (RepositoryTreeNode) ssel.getFirstElement();
+ reload(repoNode.getRepository());
+ }
+ }
+ }
+
+ private void showResource(final IResource resource) {
+ IProject project = resource.getProject();
+ RepositoryMapping mapping = RepositoryMapping.getMapping(project);
+ if (mapping == null)
+ return;
+ if (mapping.getRepository() != currentRepository) {
+ reload(mapping.getRepository());
+ }
+ }
+
+ private void attachListeners(Repository repository) {
+ myListeners.add(repository.getListenerList()
+ .addIndexChangedListener(myIndexChangedListener));
+ myListeners.add(repository.getListenerList()
+ .addRefsChangedListener(myRefsChangedListener));
+ }
+
+ private void removeListeners() {
+ for (ListenerHandle lh : myListeners)
+ lh.remove();
+ myListeners.clear();
+ }
+
+ private void stage(IStructuredSelection selection) {
+ runCommand("org.eclipse.egit.ui.team.AddToIndex", selection); //$NON-NLS-1$
+ }
+
+ private void unstage(IStructuredSelection selection) {
+ }
+
+ private static boolean runCommand(String commandId,
+ IStructuredSelection selection) {
+ ICommandService commandService = (ICommandService) PlatformUI
+ .getWorkbench().getService(ICommandService.class);
+ Command cmd = commandService.getCommand(commandId);
+ if (!cmd.isDefined()) {
+ return false;
+ }
+
+ IHandlerService handlerService = (IHandlerService) PlatformUI
+ .getWorkbench().getService(IHandlerService.class);
+ EvaluationContext c = null;
+ if (selection != null) {
+ c = new EvaluationContext(handlerService
+ .createContextSnapshot(false), selection.toList());
+ c.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection);
+ }
+ try {
+ if (c != null) {
+ handlerService.executeCommandInContext(
+ new ParameterizedCommand(cmd, null), null, c);
+ } else {
+ handlerService.executeCommand(commandId, null);
+ }
+ return true;
+ } catch (ExecutionException e) {
+ } catch (NotDefinedException e) {
+ } catch (NotEnabledException e) {
+ } catch (NotHandledException e) {
+ }
+ return false;
+ }
+
+ // TODO move to a Job?
+ private IndexDiff reload(final Repository repository) {
+ currentRepository = repository;
+
+
+ final IndexDiff indexDiff;
+ try {
+ // TODO IteratorService.createInitialIterator(repository)?
+ FileTreeIterator fileTreeIterator = new FileTreeIterator(repository);
+ indexDiff = new IndexDiff(repository, Constants.HEAD,
+ fileTreeIterator);
+ indexDiff.diff();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ removeListeners();
+ attachListeners(repository);
+
+ unstagedTableViewer.getTable().getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ if (!unstagedTableViewer.getTable().isDisposed())
+ unstagedTableViewer.setInput(new Object[] { repository, indexDiff });
+ if (!stagedTableViewer.getTable().isDisposed())
+ stagedTableViewer.setInput(new Object[] { repository, indexDiff });
+ if (!commitButton.isDisposed())
+ commitButton.setEnabled(repository.getRepositoryState().canCommit());
+ if (!authorText.isDisposed())
+ updateAuthorAndCommitter(repository);
+ if (!commitMessageText.isDisposed())
+ updateCommitMessage(repository);
+ if (!repositoryLabel.isDisposed()) {
+ repositoryLabel.setText(StagingView.getRepositoryName(repository));
+ }
+ }
+ });
+
+ return indexDiff;
+ }
+
+ private static String getRepositoryName(Repository repository) {
+ String repoName = Activator.getDefault().getRepositoryUtil()
+ .getRepositoryName(repository);
+ RepositoryState state = repository.getRepositoryState();
+ if (state != RepositoryState.SAFE)
+ return repoName + '|' + state.getDescription();
+ else
+ return repoName;
+ }
+
+ private void updateAuthorAndCommitter(Repository repository) {
+ final UserConfig config = repository.getConfig().get(UserConfig.KEY);
+
+ String author;
+ if (repository.getRepositoryState() == RepositoryState.CHERRY_PICKING_RESOLVED)
+ author = getCherryPickOriginalAuthor(repository);
+ else {
+ author = config.getAuthorName();
+ final String authorEmail = config.getAuthorEmail();
+ author = author + " <" + authorEmail + ">"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ String committer = config.getCommitterName();
+ final String committerEmail = config.getCommitterEmail();
+ committer = committer + " <" + committerEmail + ">"; //$NON-NLS-1$ //$NON-NLS-2$
+
+ authorText.setText(author);
+ committerText.setText(committer);
+ }
+
+ private void updateCommitMessage(Repository repository) {
+ if (repository.getRepositoryState() == RepositoryState.MERGING_RESOLVED
+ || repository.getRepositoryState() == RepositoryState.CHERRY_PICKING_RESOLVED)
+ commitMessageText.setText(getMergeResolveMessage(repository));
+ }
+
+ private String getCherryPickOriginalAuthor(Repository mergeRepository) {
+ try {
+ ObjectId cherryPickHead = mergeRepository.readCherryPickHead();
+ PersonIdent author = new RevWalk(mergeRepository).parseCommit(cherryPickHead).getAuthorIdent();
+ return author.getName() + " <" + author.getEmailAddress() + ">"; //$NON-NLS-1$//$NON-NLS-2$
+ } catch (IOException e) {
+ Activator.handleError(UIText.CommitAction_errorRetrievingCommit, e,
+ true);
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private String getMergeResolveMessage(Repository mergeRepository) {
+ File mergeMsg = new File(mergeRepository.getDirectory(), Constants.MERGE_MSG);
+ FileReader reader;
+ try {
+ reader = new FileReader(mergeMsg);
+ BufferedReader br = new BufferedReader(reader);
+ try {
+ StringBuilder message = new StringBuilder();
+ String s;
+ String newLine = newLine();
+ while ((s = br.readLine()) != null) {
+ message.append(s).append(newLine);
+ }
+ return message.toString();
+ } catch (IOException e) {
+ MessageDialog.openError(getSite().getShell(),
+ UIText.CommitAction_MergeHeadErrorTitle,
+ UIText.CommitAction_ErrorReadingMergeMsg);
+ throw new IllegalStateException(e);
+ } finally {
+ try {
+ br.close();
+ } catch (IOException e) {
+ // Empty
+ }
+ }
+ } catch (FileNotFoundException e) {
+ MessageDialog.openError(getSite().getShell(),
+ UIText.CommitAction_MergeHeadErrorTitle,
+ UIText.CommitAction_MergeHeadErrorMessage);
+ throw new IllegalStateException(e);
+ }
+ }
+
+ private String newLine() {
+ return System.getProperty("line.separator"); //$NON-NLS-1$
+ }
+
+ @Override
+ public void setFocus() {
+ unstagedTableViewer.getControl().setFocus();
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+
+ ISelectionService srv = (ISelectionService) getSite().getService(
+ ISelectionService.class);
+ srv.removePostSelectionListener(selectionChangedListener);
+
+ removeListeners();
+ }
+
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingViewContentProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingViewContentProvider.java
new file mode 100644
index 0000000..192934f
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingViewContentProvider.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Bernard Leach <leachbj@bouncycastle.org>
+ *
+ * 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.staging;
+
+import java.util.Comparator;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jgit.lib.IndexDiff;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * ContentProvider for staged and unstaged table nodes
+ */
+public class StagingViewContentProvider implements
+ IStructuredContentProvider {
+ private StagingEntry[] content;
+ private boolean isWorkspace;
+
+ StagingViewContentProvider(boolean workspace) {
+ this.isWorkspace = workspace;
+ }
+
+ public Object[] getElements(Object inputElement) {
+ return content;
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput,
+ Object newInput) {
+ if (newInput != null) {
+
+ Repository repository = (Repository)((Object[])newInput)[0];
+ IndexDiff indexDiff = (IndexDiff)((Object[])newInput)[1];
+
+ Set<StagingEntry> nodes = new TreeSet<StagingEntry>(new Comparator<StagingEntry>() {
+ public int compare(StagingEntry o1, StagingEntry o2) {
+ return o1.getPath().compareTo(o2.getPath());
+ }
+ });
+
+ if (isWorkspace) {
+ for (String file : indexDiff.getMissing())
+ nodes.add(new StagingEntry(repository, StagingEntry.State.MISSING, file));
+ for (String file : indexDiff.getModified()) {
+ if (indexDiff.getChanged().contains(file))
+ nodes.add(new StagingEntry(repository, StagingEntry.State.PARTIALLY_MODIFIED, file));
+ else
+ nodes.add(new StagingEntry(repository, StagingEntry.State.MODIFIED, file));
+ }
+ for (String file : indexDiff.getUntracked())
+ nodes.add(new StagingEntry(repository, StagingEntry.State.UNTRACKED, file));
+ for (String file : indexDiff.getConflicting())
+ nodes.add(new StagingEntry(repository, StagingEntry.State.CONFLICTING, file));
+ } else {
+ for (String file : indexDiff.getAdded())
+ nodes.add(new StagingEntry(repository, StagingEntry.State.ADDED, file));
+ for (String file : indexDiff.getChanged())
+ nodes.add(new StagingEntry(repository, StagingEntry.State.CHANGED, file));
+ for (String file : indexDiff.getRemoved())
+ nodes.add(new StagingEntry(repository, StagingEntry.State.REMOVED, file));
+ }
+ content = nodes.toArray(new StagingEntry[nodes.size()]);
+ }
+ }
+
+ public void dispose() {
+ // nothing to dispose
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingViewLabelProvider.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingViewLabelProvider.java
new file mode 100644
index 0000000..7954cb8
--- /dev/null
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/staging/StagingViewLabelProvider.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (C) 2011, Bernard Leach <leachbj@bouncycastle.org>
+ *
+ * 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.staging;
+
+import org.eclipse.core.runtime.Path;
+import org.eclipse.egit.ui.UIIcons;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.resource.LocalResourceManager;
+import org.eclipse.jface.resource.ResourceManager;
+import org.eclipse.jface.viewers.BaseLabelProvider;
+import org.eclipse.jface.viewers.DecorationOverlayIcon;
+import org.eclipse.jface.viewers.IDecoration;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Label provider for {@link StagingEntry} objects
+ */
+public class StagingViewLabelProvider extends BaseLabelProvider implements
+ ITableLabelProvider {
+
+ private Image DEFAULT = PlatformUI.getWorkbench().getSharedImages()
+ .getImage(ISharedImages.IMG_OBJ_FILE);
+
+ private ResourceManager resourceManager = new LocalResourceManager(
+ JFaceResources.getResources());
+
+ public Image getColumnImage(Object element, int columnIndex) {
+ if (columnIndex == 0) {
+ final StagingEntry c = (StagingEntry) element;
+ switch (c.getState()) {
+ case ADDED:
+ return getDecoratedImage(getEditorImage(c),
+ UIIcons.OVR_STAGED_ADD);
+ case CHANGED:
+ return getDecoratedImage(getEditorImage(c), UIIcons.OVR_DIRTY);
+ case REMOVED:
+ return getDecoratedImage(getEditorImage(c),
+ UIIcons.OVR_STAGED_REMOVE);
+ case MISSING:
+ return getDecoratedImage(getEditorImage(c),
+ UIIcons.OVR_STAGED_REMOVE);
+ case MODIFIED:
+ return getEditorImage(c);
+ case PARTIALLY_MODIFIED:
+ return getDecoratedImage(getEditorImage(c), UIIcons.OVR_DIRTY);
+ case CONFLICTING:
+ return getDecoratedImage(getEditorImage(c), UIIcons.OVR_CONFLICT);
+ case UNTRACKED:
+ return getDecoratedImage(getEditorImage(c), UIIcons.OVR_UNTRACKED);
+ default:
+ return getEditorImage(c);
+ }
+ }
+ return null;
+ }
+
+ public String getColumnText(Object element, int columnIndex) {
+ if (columnIndex == 0) {
+ final StagingEntry c = (StagingEntry) element;
+ if (c.getState() == StagingEntry.State.MODIFIED || c.getState() == StagingEntry.State.PARTIALLY_MODIFIED)
+ return "> " + c.getPath(); //$NON-NLS-1$
+ else
+ return c.getPath();
+ }
+ return null;
+ }
+
+ @Override
+ public void dispose() {
+ this.resourceManager.dispose();
+ super.dispose();
+ }
+
+ private Image getEditorImage(StagingEntry diff) {
+ Image image = DEFAULT;
+ String name = new Path(diff.getPath()).lastSegment();
+ if (name != null) {
+ ImageDescriptor descriptor = PlatformUI.getWorkbench()
+ .getEditorRegistry().getImageDescriptor(name);
+ image = (Image) this.resourceManager.get(descriptor);
+ }
+ return image;
+ }
+
+ private Image getDecoratedImage(Image base, ImageDescriptor decorator) {
+ DecorationOverlayIcon decorated = new DecorationOverlayIcon(base,
+ decorator, IDecoration.BOTTOM_RIGHT);
+ return (Image) this.resourceManager.get(decorated);
+ }
+}
diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
index 94d6ec8..2ce768b 100644
--- a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
+++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/uitext.properties
@@ -1228,3 +1228,13 @@ OpenWorkingFileAction_text=&Open
OpenWorkingFileAction_tooltip=Open Working File
OpenWorkingFileAction_openWorkingFileShellTitle=Problems Opening Working File
DecoratableResourceHelper_noHead=NO-HEAD
+
+StagingView_UnstagedChanges=Unstaged Changes
+StagingView_StagedChanges=Staged Changes
+StagingView_CommitMessage=Commit Message
+StagingView_Committer=Committer:
+StagingView_Author=Author:
+StagingView_Ammend_Previous_Commit=Amend Previous Commit
+StagingView_Add_Signed_Off_By=Add Signed-off-by
+StagingView_Add_Change_ID=Add Change-ID
+StagingView_Commit=Commit