Skip to main content
summaryrefslogtreecommitdiffstats
blob: 42d3d86aa808d3213446c9f151f26f515885e4cc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
/*******************************************************************************
 * Copyright (c) 2006, 2007 IBM Corporation 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:
 * IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.team.internal.ui.history;

import java.util.*;

import org.eclipse.compare.CompareUI;
import org.eclipse.compare.ITypedElement;
import org.eclipse.compare.structuremergeviewer.*;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.graphics.Image;
import org.eclipse.team.core.TeamException;
import org.eclipse.team.core.history.IFileRevision;
import org.eclipse.team.internal.core.history.LocalFileHistory;
import org.eclipse.team.internal.ui.*;
import org.eclipse.team.internal.ui.actions.CompareRevisionAction;
import org.eclipse.team.internal.ui.synchronize.LocalResourceTypedElement;
import org.eclipse.team.ui.history.*;
import org.eclipse.ui.IWorkbenchPage;

/**
 * A history page for a sub-element of a file. 
 * <p>
 * If the site is modal, the local edition is created up-front and destroyed when the page is destroyed.
 * Otherwise, the local edition is only created when needed. The {@link #getCompareInput(Object)} and
 * {@link #prepareInput(ICompareInput, org.eclipse.compare.CompareConfiguration, IProgressMonitor)}
 * methods are only used when the site is modal so they can use the localEdition.
 */
public class EditionHistoryPage extends LocalHistoryPage {
	
	private final IFile file;
	private final Object element;
	private final LocalResourceTypedElement localFileElement;
	private IStructureCreator structureCreator;
	private Map editions = new HashMap();
	private ITypedElement localEdition;
	private String name;
	
	class CompareEditionAction extends CompareRevisionAction {
		
		public CompareEditionAction(HistoryPage page) {
			super(page);
		}

		protected ITypedElement getElementFor(IResource resource) {
			if (resource.equals(file))
				return localFileElement;
			return super.getElementFor(resource);
		}
		
		protected CompareFileRevisionEditorInput createCompareEditorInput(ITypedElement left, ITypedElement right, IWorkbenchPage page) {
			ITypedElement leftEdition = getEdition(left);
			boolean leftIsLocal = false;
			if (leftEdition == null && left instanceof LocalResourceTypedElement) {
				leftEdition = createLocalEdition(structureCreator, localFileElement, element);
				leftIsLocal = true;
			}
			ITypedElement rightEdition = getEdition(right);
			return new CompareEditionsEditorInput(structureCreator, left, right, leftEdition, rightEdition, leftIsLocal, page);
		}

		private ITypedElement getEdition(ITypedElement input) {
			if (input instanceof FileRevisionTypedElement) {
				FileRevisionTypedElement te = (FileRevisionTypedElement) input;
				return getEditionFor(te.getRevision());
			}
			return null;
		}
	}
	
	static class CompareEditionsEditorInput extends CompareFileRevisionEditorInput {

		private final ITypedElement leftRevision;
		private final ITypedElement rightRevision;
		private final boolean leftIsLocal;
		private IStructureCreator structureCreator;

		public CompareEditionsEditorInput(IStructureCreator structureCreator, ITypedElement left,
				ITypedElement right, ITypedElement leftEdition,
				ITypedElement rightEdition, boolean leftIsLocal, IWorkbenchPage page) {
			super(leftEdition, rightEdition, page);
			this.structureCreator = structureCreator;
			leftRevision = left;
			rightRevision = right;
			this.leftIsLocal = leftIsLocal;
		}
		
		public LocalResourceTypedElement getLocalElement() {
			if (leftRevision instanceof LocalResourceTypedElement) {
				return (LocalResourceTypedElement) leftRevision;
			}
			return super.getLocalElement();
		}
		
		protected FileRevisionTypedElement getRightRevision() {
			if (rightRevision instanceof FileRevisionTypedElement) {
				return (FileRevisionTypedElement) rightRevision;
			}
			return null;
		}

		protected FileRevisionTypedElement getLeftRevision() {
			if (leftRevision instanceof FileRevisionTypedElement) {
				return (FileRevisionTypedElement) leftRevision;
			}
			return null;
		}
		public Object getAdapter(Class adapter) {
			if (adapter == IFile.class)
				return null;
			return super.getAdapter(adapter);
		}
		
		protected void handleDispose() {
			if (leftIsLocal && structureCreator != null)
				internalDestroy(structureCreator, getLeft());
			structureCreator = null;
			super.handleDispose();
		}
	}
	
	public static ITypedElement getPreviousState(IFile file, Object element) throws TeamException {
		LocalResourceTypedElement localFileElement= new LocalResourceTypedElement(file);
		IStructureCreator structureCreator = CompareUI.createStructureCreator(localFileElement);
		if (structureCreator == null)
			return null;
		LocalFileHistory history = new LocalFileHistory(file, false);
		history.refresh(new NullProgressMonitor());
		IFileRevision[] revisions = history.getFileRevisions();
		if (revisions.length == 0)
			return null;
		sortDescending(revisions);
		ITypedElement localEdition = null;
		try {
			localEdition = createLocalEdition(structureCreator, localFileElement, element);
			for (int i = 0; i < revisions.length; i++) {
				IFileRevision revision = revisions[i];
				ITypedElement edition = createEdition(structureCreator, element, new FileRevisionTypedElement(revision));
				if (edition != null && !contentsEqual(structureCreator, localEdition, edition)) {
					return edition;
				}
			}
		} finally {
			if (localEdition != null)
				destroyLocalEdition(structureCreator, localFileElement, localEdition);
		}
		return null;
	}
	
	public EditionHistoryPage(IFile file, Object element) {
		super(ON | ALWAYS);
		Assert.isNotNull(file);
		Assert.isNotNull(element);
		this.file = file;
		this.element = element;
		this.localFileElement= new LocalResourceTypedElement(getFile());
		structureCreator = CompareUI.createStructureCreator(localFileElement);
	}

	public void setSite(IHistoryPageSite site) {
		super.setSite(site);
		// If the site is modal, create the local edition
		if (site.isModal()) {
			localEdition = createLocalEdition(structureCreator, localFileElement, element);
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.internal.ui.history.LocalHistoryPage#getFile()
	 */
	protected IFile getFile() {
		return file;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.team.internal.ui.history.LocalHistoryPage#update(org.eclipse.team.core.history.IFileRevision[], org.eclipse.core.runtime.IProgressMonitor)
	 */
	protected void update(IFileRevision[] revisions, IProgressMonitor monitor) {
		monitor.beginTask(null, 100);
		ITypedElement te = null;
		try {
			if (localEdition == null) {
				te = createLocalEdition(structureCreator, localFileElement, element);
			} else {
				te = localEdition;
			}
			if (te != null) {
				String oldValue = getName();
				String oldDesc = getDescription();
				name = te.getName();
				IFileRevision[] filtered = filterRevisions(te, revisions, Policy.subMonitorFor(monitor, 75));
				super.update(filtered, Policy.subMonitorFor(monitor, 25));
				firePropertyChange(this, IHistoryPage.P_NAME, oldValue, getName());
				firePropertyChange(this, IHistoryPage.P_DESCRIPTION, oldDesc, getDescription());
			}
		} finally {
			if (localEdition == null && te != null)
				internalDestroy(structureCreator, te);
			monitor.done();
		}
	}

	private IFileRevision[] filterRevisions(ITypedElement localEdition, IFileRevision[] revisions,
			IProgressMonitor monitor) {
		ITypedElement previousEdition = localEdition;
		List result = new ArrayList();
		sortDescending(revisions);
		editions.clear();
		for (int i = 0; i < revisions.length; i++) {
			IFileRevision revision = revisions[i];
			ITypedElement edition = createEdition(new FileRevisionTypedElement(revision));
			if (edition != null && !contentsEqual(structureCreator, previousEdition, edition)) {
				editions.put(revision, edition);
				previousEdition = edition;
				result.add(revision);
			}
		}
		return (IFileRevision[]) result.toArray(new IFileRevision[result.size()]);
	}
	
	private static void sortDescending(IFileRevision[] revisions) {
		Arrays.sort(revisions, new Comparator() {
			public int compare(Object o1, Object o2) {
				IFileRevision d1= (IFileRevision) o1;
				IFileRevision d2= (IFileRevision) o2;
				long d= d2.getTimestamp() - d1.getTimestamp();
				if (d < 0)
					return -1;
				if (d > 0)
					return 1;
				return 0;
			}
		});
	}

	private static boolean contentsEqual(IStructureCreator creator, ITypedElement previousEdition,
			ITypedElement edition) {
		if (previousEdition == null || creator == null || edition == null)
			return false;
		String contents1 = creator.getContents(previousEdition, false /* TODO: Ignore whitespace */);
		String contents2 = creator.getContents(edition, false /* TODO: Ignore whitespace */);
		return (contents1 != null && contents2 != null && contents1.equals(contents2));
	}

	/* (non-Javadoc)
	 * @see org.eclipse.team.internal.ui.history.LocalHistoryPage#getCompareInput(java.lang.Object)
	 */
	public ICompareInput getCompareInput(Object object) {
		ITypedElement edition = getEditionFor(object);
		if (edition != null && localEdition != null)
			return new DiffNode(localEdition, edition);
		return null;
	}

	public ITypedElement getEditionFor(Object object) {
		return (ITypedElement)editions.get(object);
	}
	
	private static ITypedElement createLocalEdition(IStructureCreator creator, ITypedElement input, Object element) {
		if (creator == null)
			return null;
		ITypedElement result = null;
		if (creator instanceof IStructureCreator2) {
			IStructureCreator2 sc2 = (IStructureCreator2) creator;
			try {
				result = sc2.createElement(element, input, null);
			} catch (CoreException e) {
				TeamUIPlugin.log(e);
			}
		}
		if (result == null) {
			result = createEdition(creator, element, input);
		}
		return result;
	}
	
	private ITypedElement createEdition(ITypedElement input) {
		return createEdition(structureCreator, element, input);
	}
	
	private static ITypedElement createEdition(IStructureCreator creator, Object element, ITypedElement input) {
		if (creator == null)
			return null;
		IStructureComparator edition = creator.locate(element, input);
		if (edition instanceof ITypedElement)
			return (ITypedElement) edition;
		return null;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.internal.ui.history.LocalHistoryPage#isValidInput(java.lang.Object)
	 */
	public boolean isValidInput(Object object) {
		// This page doesn't support input changes
		return object.equals(element);
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.internal.ui.history.LocalHistoryPage#dispose()
	 */
	public void dispose() {
		try {
			disconnect();
		} finally {
			super.dispose();
		}
	}
	
	private void disconnect() {
		if (localFileElement != null)
			localFileElement.discardBuffer();
		internalDestroy(structureCreator, localEdition);
		localEdition = null;
		structureCreator = null;
	}

	private static void internalDestroy(IStructureCreator creator, ITypedElement te) {
		if (te != null && creator instanceof IStructureCreator2) {
			IStructureCreator2 sc2 = (IStructureCreator2) creator;
			sc2.destroy(te);
		}
	}
	
	private static void destroyLocalEdition(
			IStructureCreator structureCreator, LocalResourceTypedElement localFileElement, ITypedElement localEdition) {
		if (localFileElement != null)
			localFileElement.discardBuffer();
		if (localEdition != null && structureCreator instanceof IStructureCreator2) {
			IStructureCreator2 sc2 = (IStructureCreator2) structureCreator;
			sc2.destroy(localEdition);
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.internal.ui.history.LocalHistoryPage#getNoChangesMessage()
	 */
	protected String getNoChangesMessage() {
		if (name != null)
			return NLS.bind(TeamUIMessages.EditionHistoryPage_0, name);
		return TeamUIMessages.EditionHistoryPage_1;
	}
	
	protected Image getImage(Object object) {
		if (object == localEdition)
			return localEdition.getImage();
		Object revision = getRevisionFor(object);
		if (revision != null)
			return super.getImage(revision);
		return super.getImage(object);
	}
	
	protected String getLabel(Object object) {
		Object revision = getRevisionFor(object);
		if (revision != null)
			return super.getLabel(revision);
		return super.getLabel(object);
	}

	private Object getRevisionFor(Object object) {
		if (object == localEdition)
			return localFileElement;
		for (Iterator iterator = editions.keySet().iterator(); iterator.hasNext();) {
			IFileRevision revision = (IFileRevision) iterator.next();
			if (editions.get(revision) == object) {
				return revision;
			}
		}
		return null;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.internal.ui.history.LocalHistoryPage#getName()
	 */
	public String getName() {
		if (name != null)
			return name;
		return super.getName();
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.internal.ui.history.LocalHistoryPage#getDescription()
	 */
	public String getDescription() {
		if (name != null)
			return NLS.bind(TeamUIMessages.EditionHistoryPage_2, name);
		return super.getDescription();
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.team.internal.ui.history.LocalHistoryPage#createCompareAction()
	 */
	protected CompareRevisionAction createCompareAction() {
		return new CompareEditionAction(this);
	}

}

Back to the top