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 |
} |