CompareEditor: Show diffs for changed files under a new or deleted directory.
[egit/zawir.git] / org.spearce.egit.ui / src / org / spearce / egit / ui / internal / GitCompareFileRevisionEditorInput.java
blobd72093b3fd5c7e7c25a4aaf202b27da930ced903
1 /*******************************************************************************
2 * Copyright (c) 2006 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Eclipse Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/epl-v10.html
8 * Contributors:
9 * IBM Corporation - initial API and implementation
10 * Robin Rosenberg - Git interface
11 *******************************************************************************/
12 package org.spearce.egit.ui.internal;
14 import java.lang.reflect.InvocationTargetException;
16 import org.eclipse.compare.CompareConfiguration;
17 import org.eclipse.compare.CompareEditorInput;
18 import org.eclipse.compare.IEditableContent;
19 import org.eclipse.compare.IResourceProvider;
20 import org.eclipse.compare.ITypedElement;
21 import org.eclipse.compare.structuremergeviewer.DiffNode;
22 import org.eclipse.compare.structuremergeviewer.Differencer;
23 import org.eclipse.compare.structuremergeviewer.ICompareInput;
24 import org.eclipse.compare.structuremergeviewer.IDiffElement;
25 import org.eclipse.compare.structuremergeviewer.IStructureComparator;
26 import org.eclipse.core.resources.IFile;
27 import org.eclipse.core.resources.IFileState;
28 import org.eclipse.core.resources.IResource;
29 import org.eclipse.core.resources.IStorage;
30 import org.eclipse.core.runtime.CoreException;
31 import org.eclipse.core.runtime.IProgressMonitor;
32 import org.eclipse.core.runtime.NullProgressMonitor;
33 import org.eclipse.osgi.util.NLS;
34 import org.eclipse.team.internal.core.history.LocalFileRevision;
35 import org.eclipse.team.internal.ui.TeamUIMessages;
36 import org.eclipse.team.internal.ui.TeamUIPlugin;
37 import org.eclipse.team.internal.ui.Utils;
38 import org.eclipse.team.internal.ui.history.FileRevisionTypedElement;
39 import org.eclipse.team.internal.ui.synchronize.LocalResourceTypedElement;
40 import org.eclipse.ui.IWorkbenchPage;
42 /**
43 * The input provider for the compare editor when working on resources
44 * under Git control.
46 public class GitCompareFileRevisionEditorInput extends CompareEditorInput {
48 private ITypedElement left;
49 private ITypedElement right;
51 /**
52 * Creates a new CompareFileRevisionEditorInput.
53 * @param left
54 * @param right
55 * @param page
57 public GitCompareFileRevisionEditorInput(ITypedElement left, ITypedElement right, IWorkbenchPage page) {
58 super(new CompareConfiguration());
59 this.left = left;
60 this.right = right;
63 FileRevisionTypedElement getRightRevision() {
64 if (right instanceof FileRevisionTypedElement) {
65 return (FileRevisionTypedElement) right;
67 return null;
70 FileRevisionTypedElement getLeftRevision() {
71 if (left instanceof FileRevisionTypedElement) {
72 return (FileRevisionTypedElement) left;
74 return null;
77 private static void ensureContentsCached(FileRevisionTypedElement left, FileRevisionTypedElement right,
78 IProgressMonitor monitor) {
79 if (left != null) {
80 try {
81 left.cacheContents(monitor);
82 } catch (CoreException e) {
83 TeamUIPlugin.log(e);
86 if (right != null) {
87 try {
88 right.cacheContents(monitor);
89 } catch (CoreException e) {
90 TeamUIPlugin.log(e);
95 private boolean isLeftEditable(ICompareInput input) {
96 Object left = input.getLeft();
97 if (left instanceof IEditableContent) {
98 return ((IEditableContent) left).isEditable();
100 return false;
103 private IResource getResource(ICompareInput input) {
104 if (getLocalElement() != null) {
105 return ((IResourceProvider) getLocalElement()).getResource();
107 return null;
110 private ICompareInput createCompareInput() {
111 return compare(left, right);
114 private DiffNode compare(ITypedElement left, ITypedElement right) {
115 if (left.getType().equals(ITypedElement.FOLDER_TYPE)) {
116 // return new MyDiffContainer(null, left,right);
117 DiffNode diffNode = new DiffNode(null,Differencer.CHANGE,null,left,right);
118 ITypedElement[] lc = (ITypedElement[])((IStructureComparator)left).getChildren();
119 ITypedElement[] rc = (ITypedElement[])((IStructureComparator)right).getChildren();
120 int li=0;
121 int ri=0;
122 while (li<lc.length && ri<rc.length) {
123 ITypedElement ln = lc[li];
124 ITypedElement rn = rc[ri];
125 int compareTo = ln.getName().compareTo(rn.getName());
126 // TODO: Git ordering!
127 if (compareTo == 0) {
128 if (!ln.equals(rn))
129 diffNode.add(compare(ln,rn));
130 ++li;
131 ++ri;
132 } else if (compareTo < 0) {
133 DiffNode childDiffNode = new DiffNode(Differencer.ADDITION, null, ln, null);
134 diffNode.add(childDiffNode);
135 if (ln.getType().equals(ITypedElement.FOLDER_TYPE)) {
136 ITypedElement[] children = (ITypedElement[])((IStructureComparator)ln).getChildren();
137 if(children != null && children.length > 0) {
138 for (ITypedElement child : children) {
139 childDiffNode.add(addDirectoryFiles(child, Differencer.ADDITION));
143 ++li;
144 } else {
145 DiffNode childDiffNode = new DiffNode(Differencer.DELETION, null, null, rn);
146 diffNode.add(childDiffNode);
147 if (rn.getType().equals(ITypedElement.FOLDER_TYPE)) {
148 ITypedElement[] children = (ITypedElement[])((IStructureComparator)rn).getChildren();
149 if(children != null && children.length > 0) {
150 for (ITypedElement child : children) {
151 childDiffNode.add(addDirectoryFiles(child, Differencer.DELETION));
155 ++ri;
158 while (li<lc.length) {
159 ITypedElement ln = lc[li];
160 DiffNode childDiffNode = new DiffNode(Differencer.ADDITION, null, ln, null);
161 diffNode.add(childDiffNode);
162 if (ln.getType().equals(ITypedElement.FOLDER_TYPE)) {
163 ITypedElement[] children = (ITypedElement[])((IStructureComparator)ln).getChildren();
164 if(children != null && children.length > 0) {
165 for (ITypedElement child : children) {
166 childDiffNode.add(addDirectoryFiles(child, Differencer.ADDITION));
170 ++li;
172 while (ri<rc.length) {
173 ITypedElement rn = rc[ri];
174 DiffNode childDiffNode = new DiffNode(Differencer.DELETION, null, null, rn);
175 diffNode.add(childDiffNode);
176 if (rn.getType().equals(ITypedElement.FOLDER_TYPE)) {
177 ITypedElement[] children = (ITypedElement[])((IStructureComparator)rn).getChildren();
178 if(children != null && children.length > 0) {
179 for (ITypedElement child : children) {
180 childDiffNode.add(addDirectoryFiles(child, Differencer.DELETION));
184 ++ri;
186 return diffNode;
187 } else {
188 return new DiffNode(left, right);
192 private DiffNode addDirectoryFiles(ITypedElement elem, int diffType) {
193 ITypedElement l = null;
194 ITypedElement r = null;
195 if (diffType == Differencer.DELETION) {
196 r = elem;
197 } else {
198 l = elem;
201 if (elem.getType().equals(ITypedElement.FOLDER_TYPE)) {
202 DiffNode diffNode = null;
203 diffNode = new DiffNode(null,Differencer.CHANGE,null,l,r);
204 ITypedElement[] children = (ITypedElement[])((IStructureComparator)elem).getChildren();
205 for (ITypedElement child : children) {
206 diffNode.add(addDirectoryFiles(child, diffType));
208 return diffNode;
209 } else {
210 return new DiffNode(diffType, null, l, r);
214 private void initLabels(ICompareInput input) {
215 CompareConfiguration cc = getCompareConfiguration();
216 if(left != null && left instanceof GitResourceNode) {
217 String ci = ((GitResourceNode)left).getContentIdentifier();
218 if(ci != null) {
219 cc.setLeftLabel(ci.substring(0, 7) + "..");
222 if(right != null && right instanceof GitResourceNode) {
223 String ci = ((GitResourceNode)right).getContentIdentifier();
224 if(ci != null) {
225 cc.setRightLabel(ci.substring(0, 7) + "..");
228 if (getLeftRevision() != null) {
229 String leftLabel = getFileRevisionLabel(getLeftRevision());
230 cc.setLeftLabel(leftLabel);
231 } else if (getResource(input) != null) {
232 String label = NLS.bind(TeamUIMessages.CompareFileRevisionEditorInput_workspace, new Object[]{ input.getLeft().getName() });
233 cc.setLeftLabel(label);
235 if (getRightRevision() != null) {
236 String rightLabel = getFileRevisionLabel(getRightRevision());
237 cc.setRightLabel(rightLabel);
241 private String getFileRevisionLabel(FileRevisionTypedElement element) {
242 Object fileObject = element.getFileRevision();
243 if (fileObject instanceof LocalFileRevision){
244 return NLS.bind(TeamUIMessages.CompareFileRevisionEditorInput_localRevision, new Object[]{element.getName(), element.getTimestamp()});
245 } else {
246 return NLS.bind(TeamUIMessages.CompareFileRevisionEditorInput_repository, new Object[]{ element.getName(), element.getContentIdentifier()});
250 /* (non-Javadoc)
251 * @see org.eclipse.compare.CompareEditorInput#getToolTipText()
253 public String getToolTipText() {
254 Object[] titleObject = new Object[3];
255 titleObject[0] = getLongName(left);
256 titleObject[1] = getContentIdentifier(getLeftRevision());
257 titleObject[2] = getContentIdentifier(getRightRevision());
258 return NLS.bind(TeamUIMessages.CompareFileRevisionEditorInput_compareResourceAndVersions, titleObject);
261 /* (non-Javadoc)
262 * @see org.eclipse.compare.CompareEditorInput#getTitle()
264 public String getTitle() {
265 Object[] titleObject = new Object[3];
266 titleObject[0] = getShortName(left);
267 titleObject[1] = getContentIdentifier(getLeftRevision());
268 titleObject[2] = getContentIdentifier(getRightRevision());
269 return NLS.bind(TeamUIMessages.CompareFileRevisionEditorInput_compareResourceAndVersions, titleObject);
272 /* (non-Javadoc)
273 * @see org.eclipse.compare.CompareEditorInput#getAdapter(java.lang.Class)
275 public Object getAdapter(Class adapter) {
276 if (adapter == IFile.class || adapter == IResource.class) {
277 if (getLocalElement() != null) {
278 return getLocalElement().getResource();
280 return null;
282 return super.getAdapter(adapter);
285 private String getShortName(ITypedElement element) {
286 if (element instanceof FileRevisionTypedElement){
287 FileRevisionTypedElement fileRevisionElement = (FileRevisionTypedElement) element;
288 return fileRevisionElement.getName();
290 else if (element instanceof LocalResourceTypedElement){
291 LocalResourceTypedElement typedContent = (LocalResourceTypedElement) element;
292 return typedContent.getResource().getName();
294 return element.getName();
297 private String getLongName(ITypedElement element) {
298 if (element instanceof FileRevisionTypedElement){
299 FileRevisionTypedElement fileRevisionElement = (FileRevisionTypedElement) element;
300 return fileRevisionElement.getPath();
302 else if (element instanceof LocalResourceTypedElement){
303 LocalResourceTypedElement typedContent = (LocalResourceTypedElement) element;
304 return typedContent.getResource().getFullPath().toString();
306 return element.getName();
309 private String getContentIdentifier(ITypedElement element){
310 if (element instanceof FileRevisionTypedElement){
311 FileRevisionTypedElement fileRevisionElement = (FileRevisionTypedElement) element;
312 Object fileObject = fileRevisionElement.getFileRevision();
313 if (fileObject instanceof LocalFileRevision){
314 try {
315 IStorage storage = ((LocalFileRevision) fileObject).getStorage(new NullProgressMonitor());
316 if (Utils.getAdapter(storage, IFileState.class) != null){
317 //local revision
318 return TeamUIMessages.CompareFileRevisionEditorInput_0;
319 } else if (Utils.getAdapter(storage, IFile.class) != null) {
320 //current revision
321 return TeamUIMessages.CompareFileRevisionEditorInput_1;
323 } catch (CoreException e) {
325 } else {
326 return fileRevisionElement.getContentIdentifier();
329 return TeamUIMessages.CompareFileRevisionEditorInput_2;
332 // /* (non-Javadoc)
333 // * @see org.eclipse.team.ui.synchronize.LocalResourceCompareEditorInput#fireInputChange()
334 // */
335 // protected void fireInputChange() {
336 // ((DiffNode)getCompareResult()).fireChange();
337 // }
339 // /* (non-Javadoc)
340 // * @see org.eclipse.team.ui.synchronize.SaveableCompareEditorInput#contentsCreated()
341 // */
342 // protected void contentsCreated() {
343 // super.contentsCreated();
344 // notifier.initialize();
345 // }
347 // /* (non-Javadoc)
348 // * @see org.eclipse.team.ui.synchronize.SaveableCompareEditorInput#handleDispose()
349 // */
350 // protected void handleDispose() {
351 // super.handleDispose();
352 // notifier.dispose();
353 // if (getLocalElement() != null) {
354 // getLocalElement().discardBuffer();
355 // }
356 // }
358 private LocalResourceTypedElement getLocalElement() {
359 if (left instanceof LocalResourceTypedElement) {
360 return (LocalResourceTypedElement) left;
362 return null;
365 protected Object prepareInput(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
366 ICompareInput input = createCompareInput();
367 getCompareConfiguration().setLeftEditable(isLeftEditable(input));
368 getCompareConfiguration().setRightEditable(false);
369 ensureContentsCached(getLeftRevision(), getRightRevision(), monitor);
370 initLabels(input);
371 setTitle(NLS.bind(TeamUIMessages.SyncInfoCompareInput_title, new String[] { input.getName() }));
373 // The compare editor (Structure Compare) will show the diff filenames
374 // with their project relative path. So, no need to also show directory entries.
375 DiffNode flatDiffNode = new DiffNode(null,Differencer.CHANGE,null,left,right);
376 flatDiffView(flatDiffNode, (DiffNode) input);
378 return flatDiffNode;
381 private void flatDiffView(DiffNode rootNode, DiffNode currentNode) {
382 if(currentNode != null) {
383 IDiffElement[] dElems = currentNode.getChildren();
384 if(dElems != null) {
385 for(IDiffElement dElem : dElems) {
386 DiffNode dNode = (DiffNode) dElem;
387 if(dNode.getChildren() != null && dNode.getChildren().length > 0) {
388 flatDiffView(rootNode, dNode);
389 } else {
390 rootNode.add(dNode);