View | Details | Raw Unified | Return to bug 9109
Collapse All | Expand All

(-)plugin.xml (-2 / +18 lines)
Lines 255-268 Link Here
255
                  name="replaceWithGroup">
255
                  name="replaceWithGroup">
256
            </separator>
256
            </separator>
257
         </menu>
257
         </menu>
258
         <!--
258
         <action
259
         <action
260
               enablesFor="+"
259
               label="%ReplaceFromHistoryAction.label"
261
               label="%ReplaceFromHistoryAction.label"
260
               tooltip="%ReplaceFromHistoryAction.tooltip"
261
               class="org.eclipse.compare.internal.ReplaceWithEditionAction"
262
               class="org.eclipse.compare.internal.ReplaceWithEditionAction"
263
               tooltip="%ReplaceFromHistoryAction.tooltip"
262
               menubarPath="replaceWithMenu/replaceWithGroup"
264
               menubarPath="replaceWithMenu/replaceWithGroup"
263
               enablesFor="1"
264
               id="replaceFromHistory">
265
               id="replaceFromHistory">
265
         </action>
266
         </action>
267
         -->
266
         <action
268
         <action
267
               label="%ReplaceWithPreviousFromHistoryAction.label"
269
               label="%ReplaceWithPreviousFromHistoryAction.label"
268
               tooltip="%ReplaceWithPreviousFromHistoryAction.tooltip"
270
               tooltip="%ReplaceWithPreviousFromHistoryAction.tooltip"
Lines 271-276 Link Here
271
               enablesFor="1"
273
               enablesFor="1"
272
               id="replaceWithPreviousFromHistory">
274
               id="replaceWithPreviousFromHistory">
273
         </action>
275
         </action>
276
      </objectContribution>
277
      <objectContribution
278
            objectClass="org.eclipse.core.resources.IResource"
279
            adaptable="true"
280
            id="org.eclipse.compare.ReplaceWithEditionAction2">
281
         <action
282
               enablesFor="+"
283
               label="%ReplaceFromHistoryAction.label"
284
               class="org.eclipse.compare.internal.ReplaceWithEditionAction"
285
               tooltip="%ReplaceFromHistoryAction.tooltip"
286
               menubarPath="replaceWithMenu/replaceWithGroup"
287
               id="replaceFromHistory">
288
         </action>
289
274
      </objectContribution>
290
      </objectContribution>
275
      <objectContribution
291
      <objectContribution
276
            objectClass="org.eclipse.core.resources.IFile"
292
            objectClass="org.eclipse.core.resources.IFile"
(-)compare/org/eclipse/compare/internal/EditionAction.java (+4 lines)
Lines 85-90 Link Here
85
		fBundleName= bundleName;
85
		fBundleName= bundleName;
86
	}
86
	}
87
87
88
	protected String getBundleName() {
89
		return fBundleName;
90
	}
91
	
88
	protected boolean isEnabled(ISelection selection) {
92
	protected boolean isEnabled(ISelection selection) {
89
		return Utilities.getFiles(selection).length == 1;		// we don't support multiple selection for now
93
		return Utilities.getFiles(selection).length == 1;		// we don't support multiple selection for now
90
	}
94
	}
(-)compare/org/eclipse/compare/internal/ListDialog.java (+8 lines)
Lines 32-37 Link Here
32
		fAddCancelButton= false;
32
		fAddCancelButton= false;
33
	}
33
	}
34
34
35
	/* (non-Javadoc)
36
	 * @see org.eclipse.jface.dialogs.Dialog#okPressed()
37
	 */
38
	protected void okPressed() {
39
		setResult(((IStructuredSelection)fTableViewer.getSelection()).toList()); 
40
		
41
		super.okPressed();
42
	}
35
	public void setInput(Object input) {
43
	public void setInput(Object input) {
36
		fInput= input;
44
		fInput= input;
37
	}
45
	}
(-)compare/org/eclipse/compare/internal/ReplaceWithEditionAction.java (+257 lines)
Lines 10-20 Link Here
10
 *******************************************************************************/
10
 *******************************************************************************/
11
package org.eclipse.compare.internal;
11
package org.eclipse.compare.internal;
12
12
13
import java.text.DateFormat;
14
import java.text.MessageFormat;
15
import java.util.ArrayList;
16
import java.util.Arrays;
17
import java.util.Comparator;
18
import java.util.Date;
19
import java.util.HashSet;
20
import java.util.List;
21
import java.util.ResourceBundle;
22
import java.util.Set;
23
24
import org.eclipse.core.resources.IContainer;
25
import org.eclipse.core.resources.IFile;
26
import org.eclipse.core.resources.IFileState;
27
import org.eclipse.core.resources.IResource;
28
import org.eclipse.core.resources.IWorkspace;
29
import org.eclipse.core.resources.IWorkspaceRoot;
30
import org.eclipse.core.resources.ResourcesPlugin;
31
import org.eclipse.core.resources.WorkspaceJob;
32
import org.eclipse.core.runtime.CoreException;
33
import org.eclipse.core.runtime.IPath;
34
import org.eclipse.core.runtime.IProgressMonitor;
35
import org.eclipse.core.runtime.IStatus;
36
import org.eclipse.core.runtime.Status;
37
import org.eclipse.core.runtime.SubProgressMonitor;
38
import org.eclipse.jface.dialogs.MessageDialog;
39
import org.eclipse.jface.viewers.ISelection;
40
import org.eclipse.jface.viewers.LabelProvider;
41
import org.eclipse.swt.widgets.Shell;
42
13
43
14
public class ReplaceWithEditionAction extends EditionAction {
44
public class ReplaceWithEditionAction extends EditionAction {
45
46
	private static class FileStateWrapper {
47
		
48
		long timestamp;
49
		IFile file;
15
		
50
		
51
		public FileStateWrapper(IFile file, long timestamp) {
52
			this.file = file;
53
			this.timestamp = timestamp;
54
		}
55
	}
56
	
16
	public ReplaceWithEditionAction() {
57
	public ReplaceWithEditionAction() {
17
		super(true, "org.eclipse.compare.internal.ReplaceWithEditionAction"); //$NON-NLS-1$
58
		super(true, "org.eclipse.compare.internal.ReplaceWithEditionAction"); //$NON-NLS-1$
18
		fHelpContextId= ICompareContextIds.REPLACE_WITH_EDITION_DIALOG;
59
		fHelpContextId= ICompareContextIds.REPLACE_WITH_EDITION_DIALOG;
60
	}
61
	
62
	protected boolean isEnabled(ISelection selection) {
63
		return true;
64
	}
65
	
66
	protected void run(ISelection selection) {
67
		final ResourceBundle bundle= ResourceBundle.getBundle(getBundleName());
68
		
69
		Shell shell = CompareUIPlugin.getShell();
70
		
71
		try {
72
			
73
			// Determine what files are directly or indirectly in the current selection
74
			IFile[] selectedFiles = getFilesRecursive(selection);
75
			
76
			if (selectedFiles.length == 1) {
77
				super.run(selection);
78
				return;
79
			}
80
					
81
			// Collect every known timestamp at which any file in the selection was modified.
82
			// Include the current timestamp plus everything in the resource history.
83
			// Sort them in chronological order with the most recent changes first
84
			List fileStates = getAllFileStates(selectedFiles);
85
			
86
			Object[] states = fileStates.toArray();
87
			Comparator comparator = new Comparator() {
88
89
				public int compare(Object arg0, Object arg1) {
90
					FileStateWrapper state0 = (FileStateWrapper)arg0;
91
					FileStateWrapper state1 = (FileStateWrapper)arg1;
92
					
93
					long t0 = state0.timestamp;
94
					long t1 = state1.timestamp;
95
					return t0 > t1 ? -1 : t0 == t1 ? 0 : 1;
96
				}	
97
			}; 
98
			
99
			Arrays.sort(states, comparator);
100
			
101
			fileStates = Arrays.asList(states);
102
			
103
			// Create a dialog to let the user pick where they want to roll back to
104
			ListDialog listDialog = new ListDialog(shell);
105
			
106
			listDialog.setContentProvider(new ListContentProvider());
107
			listDialog.setInput(fileStates);
108
			listDialog.setLabelProvider(new LabelProvider() {
109
110
				/* (non-Javadoc)
111
				 * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
112
				 */
113
				public String getText(Object element) {
114
					FileStateWrapper state = ((FileStateWrapper)element); 
115
					String date = DateFormat.getDateTimeInstance().format(new Date(state.timestamp));
116
					
117
					return MessageFormat.format( bundle.getString("historyFormat"), new String[]{date, state.file.getName()});
118
				}
119
				
120
			});
121
		
122
			listDialog.setTitle(bundle.getString("selectEarliest"));
123
			
124
			listDialog.setAddCancelButton(true);
125
			listDialog.open();
126
127
			Object[] selections = listDialog.getResult();
128
			
129
			// Just exit if the user cancelled or didn't pick anything
130
			if (selections != null && selections.length == 1) { 
131
				final FileStateWrapper earliestChange = (FileStateWrapper)selections[0];
132
				
133
				IWorkspace workspace = ResourcesPlugin.getWorkspace();
134
				final IWorkspaceRoot root = workspace.getRoot();
135
				
136
				final List finalFileStates = fileStates;
137
				final Object[] finalStates = states;
138
				
139
				final String restoringFromHistoryName = bundle.getString("restoringFromHistory");
140
				
141
				WorkspaceJob workspaceJob = new WorkspaceJob(restoringFromHistoryName) {
142
					public IStatus runInWorkspace(IProgressMonitor monitor) throws CoreException {
143
							monitor.beginTask(restoringFromHistoryName, finalStates.length * 100);
144
				
145
							Set alreadyProcessed = new HashSet();
146
							
147
							for (int idx = finalFileStates.indexOf(earliestChange); idx >= 0; idx--) {
148
								FileStateWrapper next = (FileStateWrapper)finalStates[idx];
149
								IPath path = next.file.getFullPath();
150
								
151
								if (!alreadyProcessed.contains(path)) {
152
									IFile file = next.file;
153
									
154
									SubProgressMonitor subMon = new SubProgressMonitor(monitor, 100);
155
									
156
									rollback(file, earliestChange.timestamp, subMon);
157
									
158
									alreadyProcessed.add(path);
159
								} else {
160
									monitor.worked(100);
161
								}
162
							}
163
							
164
							monitor.done();
165
							
166
							return Status.OK_STATUS;
167
						}
168
						
169
					};
170
					
171
					workspaceJob.setRule(root);
172
					workspaceJob.setUser(true);
173
					workspaceJob.schedule();
174
				};
175
				
176
		} catch (CoreException e) {
177
			MessageDialog.openError(shell, bundle.getString("error"), e.toString());
178
		}
179
	}
180
	
181
	/**
182
	 * Rolls back the given file to the given time (if possible). 
183
	 * 
184
	 * @param file
185
	 * @param timestamp
186
	 * @param mon
187
	 * @throws CoreException
188
	 */
189
	public static void rollback(IFile file, long timestamp, IProgressMonitor mon) throws CoreException {
190
		if (file.getLocalTimeStamp() >= timestamp) {
191
			
192
			IFileState[] states = file.getHistory(null);
193
			
194
			IFileState mostRecent = null;
195
			long mostRecentTimestamp = 0;
196
			
197
			for (int stateIdx = 0; stateIdx < states.length; stateIdx++) {
198
				IFileState state = states[stateIdx];
199
				
200
				if (state.exists()) {
201
					long modTime = state.getModificationTime(); 
202
					if (modTime > mostRecentTimestamp && modTime < timestamp) {
203
						mostRecent = state;
204
						mostRecentTimestamp = modTime;
205
					}
206
				}
207
			}
208
			
209
			if (mostRecent != null) {
210
				file.setContents(mostRecent, true, true, mon);
211
			}
212
			
213
		}
214
	}
215
	
216
	/**
217
	 * 
218
	 * 
219
	 * @param files
220
	 * @return a List of FileStateWrappers representing all known times when the files in the given
221
	 * list were modified. This includes the current file timestamp plus everything found in the
222
	 * resource history.
223
	 */
224
	protected static List getAllFileStates(IFile[] files) throws CoreException {
225
		List result = new ArrayList(files.length);
226
		
227
		for (int idx = 0; idx < files.length; idx++) {
228
			IFile file = files[idx];
229
			if (!file.isAccessible()) {
230
				continue;
231
			}
232
			
233
			result.add(new FileStateWrapper(file, file.getLocalTimeStamp()));
234
			
235
			IFileState[] states = files[idx].getHistory(null);
236
			for (int stateIdx = 0; stateIdx < states.length; stateIdx++) {
237
				IFileState state = states[stateIdx];
238
				
239
				if (state.exists()) {
240
					result.add(new FileStateWrapper(file, state.getModificationTime()));
241
				}
242
			}
243
		}
244
		
245
		return result;
246
	}
247
	
248
	protected static IFile[] getFilesRecursive(ISelection selection) throws CoreException {
249
		List result = getFilesRecursive(Utilities.getResources(selection));
250
		return (IFile[]) result.toArray(new IFile[result.size()]);
251
	}
252
	
253
	private static List getFilesRecursive(IResource[] input) throws CoreException {
254
		List result = new ArrayList(input.length);
255
		
256
		for (int idx = 0; idx < input.length; idx++) {
257
258
			IResource resource = input[idx];
259
			
260
			if (!resource.isAccessible()) {
261
				continue;
262
			}
263
			
264
			if (resource instanceof IContainer) {
265
				IContainer container = (IContainer)resource;
266
				
267
				result.addAll(getFilesRecursive(container.members()));
268
			} 
269
			
270
			if (resource instanceof IFile) {
271
				result.add(resource);
272
			}
273
		}
274
		
275
		return result;
19
	}
276
	}
20
}
277
}
(-)compare/org/eclipse/compare/internal/ReplaceWithEditionAction.properties (-1 / +7 lines)
Lines 37-40 Link Here
37
noLocalHistoryError= No local history available for selected resource.
37
noLocalHistoryError= No local history available for selected resource.
38
replaceError=Cannot replace resource (reason: {0}).
38
replaceError=Cannot replace resource (reason: {0}).
39
39
40
taskName=Replacing
40
taskName=Replacing
41
42
43
historyFormat={0} : {1}
44
selectEarliest=Select earliest change to undo
45
restoringFromHistory=Restoring from history
46
error=Error

Return to bug 9109