1 | // Copyright 2012 Georg-August-Universität Göttingen, Germany |
---|
2 | // |
---|
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
---|
4 | // you may not use this file except in compliance with the License. |
---|
5 | // You may obtain a copy of the License at |
---|
6 | // |
---|
7 | // http://www.apache.org/licenses/LICENSE-2.0 |
---|
8 | // |
---|
9 | // Unless required by applicable law or agreed to in writing, software |
---|
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
---|
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
---|
12 | // See the License for the specific language governing permissions and |
---|
13 | // limitations under the License. |
---|
14 | |
---|
15 | package de.ugoe.cs.autoquest.tasktrees.temporalrelation.utils; |
---|
16 | |
---|
17 | import java.io.PrintStream; |
---|
18 | import java.util.HashSet; |
---|
19 | import java.util.LinkedList; |
---|
20 | import java.util.List; |
---|
21 | import java.util.Set; |
---|
22 | |
---|
23 | import de.ugoe.cs.autoquest.eventcore.gui.Scroll; |
---|
24 | import de.ugoe.cs.autoquest.tasktrees.temporalrelation.TaskComparator; |
---|
25 | import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskTraversingVisitor; |
---|
26 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask; |
---|
27 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance; |
---|
28 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IIteration; |
---|
29 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IMarkingTemporalRelationship; |
---|
30 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IOptional; |
---|
31 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ISelection; |
---|
32 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence; |
---|
33 | import de.ugoe.cs.autoquest.tasktrees.treeifc.IStructuringTemporalRelationship; |
---|
34 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask; |
---|
35 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance; |
---|
36 | import de.ugoe.cs.autoquest.tasktrees.treeifc.ITemporalRelationship; |
---|
37 | import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskPath; |
---|
38 | import difflib.Chunk; |
---|
39 | import difflib.Delta; |
---|
40 | import difflib.Patch; |
---|
41 | |
---|
42 | /** |
---|
43 | * <p> |
---|
44 | * This class represents a pair of tasks and their corresponding similarity level, respectively, |
---|
45 | * their diff level. In addition, it contains the task traversal, i.e., the flattened variants |
---|
46 | * of the compared tasks. It provides static methods to compare two tasks and get an object of this |
---|
47 | * class as result. Furthermore, it allows to adapt the contained traversals so that unmergable |
---|
48 | * subtasks are not traversed. |
---|
49 | * </p> |
---|
50 | * |
---|
51 | * @author Patrick Harms |
---|
52 | */ |
---|
53 | public class SimilarTasks { |
---|
54 | |
---|
55 | /** |
---|
56 | * default indicator for unequal tasks |
---|
57 | */ |
---|
58 | public static final SimilarTasks UNEQUAL_TASKS = new SimilarTasks(null, null, null); |
---|
59 | |
---|
60 | /** |
---|
61 | * result of the string like comparison of both task traversals |
---|
62 | */ |
---|
63 | private Patch patch; |
---|
64 | |
---|
65 | /** |
---|
66 | * the diff level resulting from the comparison |
---|
67 | */ |
---|
68 | private int diffLevel; |
---|
69 | |
---|
70 | /** |
---|
71 | * the first compared task |
---|
72 | */ |
---|
73 | private ITask leftHandSide; |
---|
74 | |
---|
75 | /** |
---|
76 | * the second compare task |
---|
77 | */ |
---|
78 | private ITask rightHandSide; |
---|
79 | |
---|
80 | /** |
---|
81 | * the traversal of the first task |
---|
82 | */ |
---|
83 | private TaskTraversal leftHandSideTraversal; |
---|
84 | |
---|
85 | /** |
---|
86 | * the traversal of the second task |
---|
87 | */ |
---|
88 | private TaskTraversal rightHandSideTraversal; |
---|
89 | |
---|
90 | /** |
---|
91 | * initialized a pair of tasks and calculates its diff level |
---|
92 | */ |
---|
93 | public SimilarTasks(Patch patch, |
---|
94 | TaskTraversal traversal1, |
---|
95 | TaskTraversal traversal2) |
---|
96 | { |
---|
97 | if (traversal1 != null) { |
---|
98 | this.leftHandSide = traversal1.getTask(); |
---|
99 | } |
---|
100 | |
---|
101 | this.leftHandSideTraversal = traversal1; |
---|
102 | |
---|
103 | if (traversal2 != null) { |
---|
104 | this.rightHandSide = traversal2.getTask(); |
---|
105 | } |
---|
106 | |
---|
107 | this.rightHandSideTraversal = traversal2; |
---|
108 | |
---|
109 | if (patch != null) { |
---|
110 | this.patch = patch; |
---|
111 | this.diffLevel = getDiffLevel(patch, traversal1, traversal2); |
---|
112 | } |
---|
113 | else { |
---|
114 | this.diffLevel = 100; |
---|
115 | } |
---|
116 | } |
---|
117 | |
---|
118 | /** |
---|
119 | * static convenience method to compare two tasks |
---|
120 | */ |
---|
121 | public static SimilarTasks compareTasks(ITask task1, |
---|
122 | ITask task2, |
---|
123 | TaskComparator comparator) |
---|
124 | { |
---|
125 | return compareTasks(task1, task2, comparator, null); |
---|
126 | } |
---|
127 | |
---|
128 | /** |
---|
129 | * static convenience method to compare two tasks but ignoring a given set of subtasks when |
---|
130 | * creating the traversals. |
---|
131 | */ |
---|
132 | public static SimilarTasks compareTasks(ITask task1, |
---|
133 | ITask task2, |
---|
134 | TaskComparator comparator, |
---|
135 | List<TaskPath> pathsNotToTraverse) |
---|
136 | { |
---|
137 | TaskTraversal traversal1 = TaskTraversal.getTraversal(task1, pathsNotToTraverse); |
---|
138 | TaskTraversal traversal2 = TaskTraversal.getTraversal(task2, pathsNotToTraverse); |
---|
139 | |
---|
140 | if ((traversal1.size() <= 0) || (traversal2.size() <= 0)) { |
---|
141 | return null; |
---|
142 | } |
---|
143 | |
---|
144 | return compareTraversals(traversal1, traversal2, comparator); |
---|
145 | } |
---|
146 | |
---|
147 | /** |
---|
148 | * <p> |
---|
149 | * TODO: comment |
---|
150 | * </p> |
---|
151 | * |
---|
152 | * @param traversal1 |
---|
153 | * @param traversal2 |
---|
154 | * @param comparator |
---|
155 | * @return |
---|
156 | */ |
---|
157 | public static SimilarTasks compareTraversals(TaskTraversal traversal1, |
---|
158 | TaskTraversal traversal2, |
---|
159 | TaskComparator comparator) |
---|
160 | { |
---|
161 | Patch patch = new TaskTraversalMyersDiff(comparator).getDiff(traversal1, traversal2); |
---|
162 | |
---|
163 | SimilarTasks result = new SimilarTasks(patch, traversal1, traversal2); |
---|
164 | |
---|
165 | return result; |
---|
166 | } |
---|
167 | |
---|
168 | |
---|
169 | /** |
---|
170 | * This method checks for mergability of the provided similar tasks and if this is not given, |
---|
171 | * it reduces the traversals by ignoring interleaving iterations and other situations until |
---|
172 | * the remaining traversals can be the basis of a merge. |
---|
173 | */ |
---|
174 | public static SimilarTasks getMergableLevelOfSimilarity(SimilarTasks source, |
---|
175 | TaskComparator comparator) |
---|
176 | { |
---|
177 | SimilarTasks similarTasks = source; |
---|
178 | |
---|
179 | List<TaskPath> pathsToIgnore = similarTasks.getPathsToIgnore(); |
---|
180 | |
---|
181 | int prevPathsToIgnoreCount = 0; |
---|
182 | |
---|
183 | do { |
---|
184 | prevPathsToIgnoreCount = pathsToIgnore.size(); |
---|
185 | |
---|
186 | similarTasks = compareTasks |
---|
187 | (similarTasks.getLeftHandSide(), similarTasks.getRightHandSide(), |
---|
188 | comparator, pathsToIgnore); |
---|
189 | |
---|
190 | // similarTasks.dump(System.out); |
---|
191 | |
---|
192 | List<TaskPath> furtherPathsToIgnore = similarTasks.getPathsToIgnore(); |
---|
193 | |
---|
194 | // System.out.println("further paths to ignore:"); |
---|
195 | // for (TaskPath path : furtherPathsToIgnore) { |
---|
196 | // System.out.println(" " + path); |
---|
197 | // } |
---|
198 | |
---|
199 | for (TaskPath pathToAdd : furtherPathsToIgnore) { |
---|
200 | boolean found = false; |
---|
201 | for (TaskPath pathToIgnore : pathsToIgnore) { |
---|
202 | if (pathToAdd.equals(pathToIgnore)) { |
---|
203 | found = true; |
---|
204 | break; |
---|
205 | } |
---|
206 | } |
---|
207 | |
---|
208 | if (!found) { |
---|
209 | pathsToIgnore.add(pathToAdd); |
---|
210 | } |
---|
211 | } |
---|
212 | } |
---|
213 | while (pathsToIgnore.size() > prevPathsToIgnoreCount); |
---|
214 | |
---|
215 | if (similarTasks.isStillWellAligned()) { |
---|
216 | return similarTasks; |
---|
217 | } |
---|
218 | else { |
---|
219 | // this may happen, if due to interleaving iterations the similarities of the task |
---|
220 | // move and the diff algorithm does not align them anymore as optimal as possible |
---|
221 | // because some similarities were lost due to not comparing all paths anymore. |
---|
222 | return null; |
---|
223 | } |
---|
224 | } |
---|
225 | |
---|
226 | /** |
---|
227 | * checks if the delta between the two traversals is at their border or not |
---|
228 | */ |
---|
229 | public boolean isInBetweenDifference() { |
---|
230 | List<Delta> deltas = patch.getDeltas(); |
---|
231 | |
---|
232 | for (Delta delta : deltas) { |
---|
233 | int origPos = delta.getOriginal().getPosition(); |
---|
234 | int origSize = delta.getOriginal().size(); |
---|
235 | int revPos = delta.getRevised().getPosition(); |
---|
236 | int revSize = delta.getRevised().size(); |
---|
237 | |
---|
238 | if ((origPos <= 0) || (revPos <= 0)) { |
---|
239 | // optional must not be the beginning of the task |
---|
240 | return false; |
---|
241 | } |
---|
242 | else if ((delta.getType() == Delta.TYPE.INSERT) && |
---|
243 | ((revPos + revSize) >= rightHandSideTraversal.size())) |
---|
244 | { |
---|
245 | // optional must not be the end of the right hand side task |
---|
246 | return false; |
---|
247 | } |
---|
248 | else if ((delta.getType() == Delta.TYPE.DELETE) && |
---|
249 | ((origPos + origSize) >= leftHandSideTraversal.size())) |
---|
250 | { |
---|
251 | // optional must not be the end of the left hand side task |
---|
252 | return false; |
---|
253 | } |
---|
254 | else if ((delta.getType() == Delta.TYPE.CHANGE) && |
---|
255 | (((revPos + revSize) >= rightHandSideTraversal.size()) || |
---|
256 | ((origPos + origSize) >= leftHandSideTraversal.size()))) |
---|
257 | { |
---|
258 | // selection must not be the end of the left hand or right hand side task |
---|
259 | return false; |
---|
260 | } |
---|
261 | } |
---|
262 | |
---|
263 | return deltas.size() > 0; |
---|
264 | } |
---|
265 | |
---|
266 | /** |
---|
267 | * <p> |
---|
268 | * TODO: comment |
---|
269 | * </p> |
---|
270 | * |
---|
271 | * @return |
---|
272 | */ |
---|
273 | public boolean isStillWellAligned() { |
---|
274 | if (isInBetweenDifference()) { |
---|
275 | return true; |
---|
276 | } |
---|
277 | else { |
---|
278 | for (Delta delta : patch.getDeltas()) { |
---|
279 | if (delta.getType() == Delta.TYPE.INSERT) { |
---|
280 | if ((delta.getOriginal().getPosition() == 0) || |
---|
281 | (delta.getOriginal().getPosition() == leftHandSideTraversal.size())) |
---|
282 | { |
---|
283 | return false; |
---|
284 | } |
---|
285 | } |
---|
286 | else if (delta.getType() == Delta.TYPE.DELETE) { |
---|
287 | if ((delta.getRevised().getPosition() == 0) || |
---|
288 | (delta.getRevised().getPosition() == rightHandSideTraversal.size())) |
---|
289 | { |
---|
290 | return false; |
---|
291 | } |
---|
292 | } |
---|
293 | } |
---|
294 | } |
---|
295 | |
---|
296 | return true; |
---|
297 | } |
---|
298 | |
---|
299 | /** |
---|
300 | * @return the patch |
---|
301 | */ |
---|
302 | public Patch getPatch() { |
---|
303 | return patch; |
---|
304 | } |
---|
305 | |
---|
306 | /** |
---|
307 | * @return the diff level |
---|
308 | */ |
---|
309 | public int getDiffLevel() { |
---|
310 | return diffLevel; |
---|
311 | } |
---|
312 | |
---|
313 | /** |
---|
314 | * @return the first task of the comparison |
---|
315 | */ |
---|
316 | public ITask getLeftHandSide() { |
---|
317 | return leftHandSide; |
---|
318 | } |
---|
319 | |
---|
320 | /** |
---|
321 | * @return the second task of the comparison |
---|
322 | */ |
---|
323 | public ITask getRightHandSide() { |
---|
324 | return rightHandSide; |
---|
325 | } |
---|
326 | |
---|
327 | /** |
---|
328 | * @return the traversal of the first task of the comparison |
---|
329 | */ |
---|
330 | public TaskTraversal getLeftHandSideTraversal() { |
---|
331 | return leftHandSideTraversal; |
---|
332 | } |
---|
333 | |
---|
334 | /** |
---|
335 | * @return the traversal of the second task of the comparison |
---|
336 | */ |
---|
337 | public TaskTraversal getRightHandSideTraversal() { |
---|
338 | return rightHandSideTraversal; |
---|
339 | } |
---|
340 | |
---|
341 | /** |
---|
342 | * returns paths to subtasks, that can not be merged. |
---|
343 | */ |
---|
344 | public List<TaskPath> getPathsToIgnore() { |
---|
345 | List<TaskPath> result = new LinkedList<TaskPath>(); |
---|
346 | Delta singleChangeDelta = null; |
---|
347 | |
---|
348 | if ((patch.getDeltas().size() == 1) && |
---|
349 | (patch.getDeltas().get(0).getType() == Delta.TYPE.CHANGE)) |
---|
350 | { |
---|
351 | singleChangeDelta = patch.getDeltas().get(0); |
---|
352 | } |
---|
353 | |
---|
354 | // if it is a full change, then the parent of either side must be fully ignored |
---|
355 | if (singleChangeDelta != null) { |
---|
356 | if ((singleChangeDelta.getOriginal().getPosition() == 0) && |
---|
357 | (singleChangeDelta.getOriginal().size() == leftHandSideTraversal.size())) |
---|
358 | { |
---|
359 | TaskPath path = new TaskPath(); |
---|
360 | path.add(leftHandSide, 0); |
---|
361 | result.add(path); |
---|
362 | } |
---|
363 | |
---|
364 | if ((singleChangeDelta.getRevised().getPosition() == 0) && |
---|
365 | (singleChangeDelta.getRevised().size() == rightHandSideTraversal.size())) |
---|
366 | { |
---|
367 | TaskPath path = new TaskPath(); |
---|
368 | path.add(rightHandSide, 0); |
---|
369 | result.add(path); |
---|
370 | } |
---|
371 | } |
---|
372 | |
---|
373 | if (result.size() < 2) { |
---|
374 | // if we do not already ignore both root tasks, check for selections and interleaving |
---|
375 | // iterations that have to be ignored if they belong to a delta |
---|
376 | for (Delta delta : patch.getDeltas()) { |
---|
377 | //getSelections(delta, result); |
---|
378 | getPathsToRealIntersectingIterations(delta, result); |
---|
379 | getNotFullyInterleavingIteration(delta, result); |
---|
380 | getPathsToParentTasksFullyInsideDelta(delta, result); |
---|
381 | } |
---|
382 | |
---|
383 | // check for any parent optional that may be empty and can hence not be flattened |
---|
384 | TaskPath tmppath = new TaskPath(); |
---|
385 | tmppath.add(leftHandSide, 0); |
---|
386 | getParentOptionals(tmppath, result); |
---|
387 | tmppath = new TaskPath(); |
---|
388 | tmppath.add(rightHandSide, 0); |
---|
389 | getParentOptionals(tmppath, result); |
---|
390 | |
---|
391 | // check if there are common subtasks on both sides that lie outside any delta and |
---|
392 | // that hence should be ignored (especially when performing flattening of task |
---|
393 | // instances later with the goal to preserve as many subtasks and respective instances) |
---|
394 | int deltaIndex = 0; |
---|
395 | int leftTraversalIndex = 0; |
---|
396 | int rightTraversalIndex = 0; |
---|
397 | Set<ITask> commonInvolvedTasks = getCommonInvolvedTasks(leftHandSide, rightHandSide); |
---|
398 | |
---|
399 | do { |
---|
400 | Delta delta = deltaIndex < patch.getDeltas().size() |
---|
401 | ? patch.getDeltas().get(deltaIndex++) : null; |
---|
402 | |
---|
403 | int nextLeftTraversalIndex = leftHandSideTraversal.size(); |
---|
404 | int nextRightTraversalIndex = rightHandSideTraversal.size(); |
---|
405 | |
---|
406 | if (delta != null) { |
---|
407 | nextLeftTraversalIndex = delta.getOriginal().getPosition() + 1; |
---|
408 | nextRightTraversalIndex = delta.getRevised().getPosition() + 1; |
---|
409 | |
---|
410 | if (delta.getType() == Delta.TYPE.INSERT) { |
---|
411 | nextLeftTraversalIndex--; |
---|
412 | } |
---|
413 | else if (delta.getType() == Delta.TYPE.DELETE) { |
---|
414 | nextRightTraversalIndex--; |
---|
415 | } |
---|
416 | } |
---|
417 | |
---|
418 | TaskPath[] leftSubTraversal = |
---|
419 | leftHandSideTraversal.subList(leftTraversalIndex, nextLeftTraversalIndex); |
---|
420 | |
---|
421 | for (TaskPath path : leftSubTraversal) { |
---|
422 | for (int i = 0; i < path.size(); i++) { |
---|
423 | if (commonInvolvedTasks.contains(path.getTask(i))) { |
---|
424 | // found a candidate. Check if the candidate does not span more than |
---|
425 | // the sub traversal |
---|
426 | TaskPath parentPath = path.subPath(0, i + 1); |
---|
427 | int[] indexes = leftHandSideTraversal.getIndexesRootedBy(parentPath); |
---|
428 | |
---|
429 | if ((indexes[0] >= leftTraversalIndex) && |
---|
430 | (indexes[1] < nextLeftTraversalIndex)) |
---|
431 | { |
---|
432 | result.add(parentPath); |
---|
433 | break; // breaks only the path but the rest of the traversal is |
---|
434 | // checked too |
---|
435 | } |
---|
436 | } |
---|
437 | } |
---|
438 | } |
---|
439 | |
---|
440 | TaskPath[] rightSubTraversal = |
---|
441 | rightHandSideTraversal.subList(rightTraversalIndex, nextRightTraversalIndex); |
---|
442 | |
---|
443 | for (TaskPath path : rightSubTraversal) { |
---|
444 | for (int i = 0; i < path.size(); i++) { |
---|
445 | if (commonInvolvedTasks.contains(path.getTask(i))) { |
---|
446 | // found a candidate. Check if the candidate does not span more than |
---|
447 | // the sub traversal |
---|
448 | TaskPath parentPath = path.subPath(0, i + 1); |
---|
449 | int[] indexes = rightHandSideTraversal.getIndexesRootedBy(parentPath); |
---|
450 | |
---|
451 | if ((indexes[0] >= rightTraversalIndex) && |
---|
452 | (indexes[1] < nextRightTraversalIndex)) |
---|
453 | { |
---|
454 | result.add(parentPath); |
---|
455 | break; // breaks only the path but the rest of the traversal is |
---|
456 | // checked too |
---|
457 | } |
---|
458 | } |
---|
459 | } |
---|
460 | } |
---|
461 | |
---|
462 | leftTraversalIndex = nextLeftTraversalIndex; |
---|
463 | rightTraversalIndex = nextRightTraversalIndex; |
---|
464 | } |
---|
465 | while (leftTraversalIndex < leftHandSideTraversal.size()); |
---|
466 | |
---|
467 | } |
---|
468 | |
---|
469 | return result; |
---|
470 | } |
---|
471 | |
---|
472 | /** |
---|
473 | * |
---|
474 | */ |
---|
475 | public void dump(PrintStream out) { |
---|
476 | out.println(); |
---|
477 | out.print("similar tasks: left "); |
---|
478 | out.print(leftHandSide); |
---|
479 | out.print(" ("); |
---|
480 | out.print(leftHandSide.getInstances().size()); |
---|
481 | out.print(" instances), right "); |
---|
482 | out.print(rightHandSide); |
---|
483 | out.print(" ("); |
---|
484 | out.print(rightHandSide.getInstances().size()); |
---|
485 | out.print(" instances), diff level "); |
---|
486 | out.println(diffLevel); |
---|
487 | |
---|
488 | out.println("left traversal"); |
---|
489 | for (TaskPath path : leftHandSideTraversal.getTraversalPaths()) { |
---|
490 | out.println(path); |
---|
491 | } |
---|
492 | |
---|
493 | out.println("right traversal"); |
---|
494 | for (TaskPath path : rightHandSideTraversal.getTraversalPaths()) { |
---|
495 | out.println(path); |
---|
496 | } |
---|
497 | |
---|
498 | if (patch != null) { |
---|
499 | out.println("deltas:"); |
---|
500 | for (Delta delta : patch.getDeltas()) { |
---|
501 | out.println(delta); |
---|
502 | } |
---|
503 | } |
---|
504 | |
---|
505 | List<String> linesLeft = new LinkedList<String>(); |
---|
506 | TaskPath path = new TaskPath(); |
---|
507 | path.add(leftHandSide, 0); |
---|
508 | dumpToLineList(path, leftHandSideTraversal, linesLeft); |
---|
509 | path.removeLast(); |
---|
510 | |
---|
511 | List<String> linesRight = new LinkedList<String>(); |
---|
512 | path.add(rightHandSide, 0); |
---|
513 | dumpToLineList(path, rightHandSideTraversal, linesRight); |
---|
514 | |
---|
515 | |
---|
516 | /*System.out.println("\n#################################################"); |
---|
517 | for (int j = 0; ((j < linesLeft.size()) || (j < linesRight.size())); j++) { |
---|
518 | String left = j < linesLeft.size() ? linesLeft.get(j) : ""; |
---|
519 | String right = j < linesRight.size() ? linesRight.get(j) : ""; |
---|
520 | |
---|
521 | StringBuffer line = new StringBuffer(); |
---|
522 | line.append(j); |
---|
523 | line.append(":\t"); |
---|
524 | line.append(left); |
---|
525 | |
---|
526 | for (int k = line.length(); k < 60; k++) { |
---|
527 | line.append(' '); |
---|
528 | } |
---|
529 | |
---|
530 | line.append(right); |
---|
531 | System.out.println(line); |
---|
532 | }*/ |
---|
533 | |
---|
534 | // change lists to have the same length depending on the changes |
---|
535 | int lineIndexLeft = 0; |
---|
536 | int lineIndexRight = 0; |
---|
537 | int leftHandTraversalIndex = 0; |
---|
538 | while (leftHandTraversalIndex < leftHandSideTraversal.size()) { |
---|
539 | |
---|
540 | //System.out.println("\n" + lineIndexLeft + " " + lineIndexRight); |
---|
541 | |
---|
542 | Delta delta = null; |
---|
543 | |
---|
544 | for (Delta candidate : patch.getDeltas()) { |
---|
545 | if (candidate.getOriginal().getPosition() == leftHandTraversalIndex) { |
---|
546 | delta = candidate; |
---|
547 | break; |
---|
548 | } |
---|
549 | } |
---|
550 | |
---|
551 | if ((delta != null) && (delta.getType() == Delta.TYPE.DELETE)) { |
---|
552 | for (int j = 0; j < delta.getOriginal().size(); j++) { |
---|
553 | while (linesLeft.get(lineIndexLeft) != null) { |
---|
554 | lineIndexLeft++; |
---|
555 | } |
---|
556 | |
---|
557 | linesLeft.remove(lineIndexLeft); |
---|
558 | |
---|
559 | while (lineIndexRight < lineIndexLeft) { |
---|
560 | linesRight.add(lineIndexRight++, null); |
---|
561 | } |
---|
562 | |
---|
563 | leftHandTraversalIndex++; |
---|
564 | } |
---|
565 | |
---|
566 | linesLeft.add(lineIndexLeft++, "-------------------------------------"); |
---|
567 | linesRight.add(lineIndexRight++, "-------------------------------------"); |
---|
568 | } |
---|
569 | else if ((delta != null) && (delta.getType() == Delta.TYPE.INSERT)) { |
---|
570 | for (int j = 0; j < delta.getRevised().size(); j++) { |
---|
571 | while (linesRight.get(lineIndexRight) != null) { |
---|
572 | lineIndexRight++; |
---|
573 | } |
---|
574 | |
---|
575 | linesRight.remove(lineIndexRight); |
---|
576 | |
---|
577 | while (lineIndexLeft < lineIndexRight) { |
---|
578 | linesLeft.add(lineIndexLeft++, null); |
---|
579 | } |
---|
580 | } |
---|
581 | |
---|
582 | // ensure that what is equal is harmonized too (because after an insert always |
---|
583 | // comes something equal). The traversal index will be updated automatically, |
---|
584 | // too. |
---|
585 | delta = null; |
---|
586 | |
---|
587 | linesLeft.add(lineIndexLeft++, "-------------------------------------"); |
---|
588 | linesRight.add(lineIndexRight++, "-------------------------------------"); |
---|
589 | } |
---|
590 | |
---|
591 | if ((delta == null) || (delta.getType() == Delta.TYPE.CHANGE)) { |
---|
592 | int chunkSizeLeft = delta != null ? delta.getOriginal().size() : 1; |
---|
593 | int chunkSizeRight = delta != null ? delta.getRevised().size() : 1; |
---|
594 | |
---|
595 | int chunksHandledLeft = 0; |
---|
596 | int chunksHandledRight = 0; |
---|
597 | |
---|
598 | for (int j = 0; j < Math.max(chunkSizeLeft, chunkSizeRight); j++) { |
---|
599 | if (chunksHandledLeft < chunkSizeLeft) { |
---|
600 | while (linesLeft.get(lineIndexLeft) != null) { |
---|
601 | lineIndexLeft++; |
---|
602 | } |
---|
603 | |
---|
604 | linesLeft.remove(lineIndexLeft); |
---|
605 | chunksHandledLeft++; |
---|
606 | } |
---|
607 | |
---|
608 | if (chunksHandledRight < chunkSizeRight) { |
---|
609 | while (linesRight.get(lineIndexRight) != null) { |
---|
610 | lineIndexRight++; |
---|
611 | } |
---|
612 | |
---|
613 | linesRight.remove(lineIndexRight); |
---|
614 | chunksHandledRight++; |
---|
615 | } |
---|
616 | |
---|
617 | while (lineIndexLeft < lineIndexRight) { |
---|
618 | linesLeft.add(lineIndexLeft++, null); |
---|
619 | } |
---|
620 | while (lineIndexRight < lineIndexLeft) { |
---|
621 | linesRight.add(lineIndexRight++, null); |
---|
622 | } |
---|
623 | } |
---|
624 | |
---|
625 | linesLeft.add(lineIndexLeft++, "-------------------------------------"); |
---|
626 | linesRight.add(lineIndexRight++, "-------------------------------------"); |
---|
627 | |
---|
628 | leftHandTraversalIndex += delta != null ? delta.getOriginal().size() : 1; |
---|
629 | } |
---|
630 | |
---|
631 | /*System.out.println(delta + " " + leftHandTraversalIndex); |
---|
632 | System.out.println("\n#################################################"); |
---|
633 | for (int j = 0; ((j < linesLeft.size()) || (j < linesRight.size())); j++) { |
---|
634 | String left = j < linesLeft.size() ? linesLeft.get(j) : ""; |
---|
635 | String right = j < linesRight.size() ? linesRight.get(j) : ""; |
---|
636 | |
---|
637 | StringBuffer line = new StringBuffer(); |
---|
638 | line.append(j); |
---|
639 | line.append(":\t"); |
---|
640 | line.append(left); |
---|
641 | |
---|
642 | for (int k = line.length(); k < 60; k++) { |
---|
643 | line.append(' '); |
---|
644 | } |
---|
645 | |
---|
646 | line.append(right); |
---|
647 | System.out.println(line); |
---|
648 | }*/ |
---|
649 | } |
---|
650 | |
---|
651 | int indentLeft = 0; |
---|
652 | int indentRight = 0; |
---|
653 | |
---|
654 | for (int i = 0; i < linesLeft.size(); i++) { |
---|
655 | StringBuffer line = new StringBuffer(); |
---|
656 | String left = linesLeft.get(i); |
---|
657 | String right = linesRight.get(i); |
---|
658 | |
---|
659 | if (left != null) { |
---|
660 | if (left.indexOf('}') >= 0) { |
---|
661 | indentLeft -= 2; |
---|
662 | } |
---|
663 | |
---|
664 | for (int j = 0; j < indentLeft; j++) { |
---|
665 | line.append(' '); |
---|
666 | } |
---|
667 | |
---|
668 | if (left.indexOf('{') >= 0) { |
---|
669 | indentLeft += 2; |
---|
670 | } |
---|
671 | |
---|
672 | line.append(left); |
---|
673 | } |
---|
674 | |
---|
675 | if (right != null) { |
---|
676 | for (int j = line.length(); j < 100; j++) { |
---|
677 | line.append(' '); |
---|
678 | } |
---|
679 | if (right.indexOf('}') >= 0) { |
---|
680 | indentRight -= 2; |
---|
681 | } |
---|
682 | |
---|
683 | for (int j = 0; j < indentRight; j++) { |
---|
684 | line.append(' '); |
---|
685 | } |
---|
686 | |
---|
687 | if (right.indexOf('{') >= 0) { |
---|
688 | indentRight += 2; |
---|
689 | } |
---|
690 | |
---|
691 | line.append(right); |
---|
692 | } |
---|
693 | |
---|
694 | out.println(line); |
---|
695 | } |
---|
696 | } |
---|
697 | |
---|
698 | /** |
---|
699 | * |
---|
700 | */ |
---|
701 | private static Set<ITask> getCommonInvolvedTasks(ITask task1, ITask task2) { |
---|
702 | Set<ITask> result = getAllInvolvedTasks(task1); |
---|
703 | result.retainAll(getAllInvolvedTasks(task2)); |
---|
704 | return result; |
---|
705 | } |
---|
706 | |
---|
707 | /** |
---|
708 | * |
---|
709 | */ |
---|
710 | private static Set<ITask> getAllInvolvedTasks(ITask task) { |
---|
711 | final Set<ITask> result = new HashSet<ITask>(); |
---|
712 | |
---|
713 | task.accept(new DefaultTaskTraversingVisitor() { |
---|
714 | @Override |
---|
715 | public void visit(IEventTask eventTask) { |
---|
716 | result.add(eventTask); |
---|
717 | } |
---|
718 | |
---|
719 | @Override |
---|
720 | public void visit(IStructuringTemporalRelationship relationship) { |
---|
721 | result.add(relationship); |
---|
722 | super.visit(relationship); |
---|
723 | } |
---|
724 | |
---|
725 | @Override |
---|
726 | public void visit(IMarkingTemporalRelationship relationship) { |
---|
727 | result.add(relationship); |
---|
728 | super.visit(relationship); |
---|
729 | } |
---|
730 | }); |
---|
731 | |
---|
732 | return result; |
---|
733 | } |
---|
734 | |
---|
735 | /** |
---|
736 | * |
---|
737 | */ |
---|
738 | private void dumpToLineList(TaskPath path, |
---|
739 | TaskTraversal traversal, |
---|
740 | List<String> lines) |
---|
741 | { |
---|
742 | boolean isTraversalElement = false; |
---|
743 | |
---|
744 | for (TaskPath candidate : traversal.getTraversalPaths()) { |
---|
745 | if (path.equals(candidate)) { |
---|
746 | isTraversalElement = true; |
---|
747 | break; |
---|
748 | } |
---|
749 | } |
---|
750 | |
---|
751 | if (isTraversalElement) { |
---|
752 | lines.add(path.getLast().toString()); |
---|
753 | lines.add(null); |
---|
754 | /*ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); |
---|
755 | PrintStream out = new PrintStream(byteStream); |
---|
756 | |
---|
757 | new TaskTreeEncoder().encode(path.getLast(), out); |
---|
758 | |
---|
759 | out.close(); |
---|
760 | |
---|
761 | BufferedReader reader = new BufferedReader |
---|
762 | (new InputStreamReader(new ByteArrayInputStream(byteStream.toByteArray()))); |
---|
763 | |
---|
764 | String line = null; |
---|
765 | do { |
---|
766 | try { |
---|
767 | line = reader.readLine(); |
---|
768 | } |
---|
769 | catch (IOException e) { |
---|
770 | // should not happen so dump hard |
---|
771 | e.printStackTrace(); |
---|
772 | } |
---|
773 | lines.add(line != null ? line.trim() : null); |
---|
774 | } |
---|
775 | while (line != null);*/ |
---|
776 | |
---|
777 | } |
---|
778 | else { |
---|
779 | ITask task = path.getLast(); |
---|
780 | if (task instanceof ITemporalRelationship) { |
---|
781 | lines.add(task + " {"); |
---|
782 | |
---|
783 | if (task instanceof IStructuringTemporalRelationship) { |
---|
784 | List<ITask> children = |
---|
785 | ((IStructuringTemporalRelationship) task).getChildren(); |
---|
786 | |
---|
787 | for (int i = 0; i < children.size(); i++) { |
---|
788 | path.add(children.get(i), i); |
---|
789 | dumpToLineList(path, traversal, lines); |
---|
790 | path.removeLast(); |
---|
791 | } |
---|
792 | } |
---|
793 | else if (task instanceof IMarkingTemporalRelationship) { |
---|
794 | IMarkingTemporalRelationship relationship = |
---|
795 | (IMarkingTemporalRelationship) task; |
---|
796 | |
---|
797 | path.add(relationship.getMarkedTask(), 0); |
---|
798 | dumpToLineList(path, traversal, lines); |
---|
799 | path.removeLast(); |
---|
800 | } |
---|
801 | |
---|
802 | if (lines.get(lines.size() - 1) != null) { |
---|
803 | lines.add("}"); |
---|
804 | } |
---|
805 | else { |
---|
806 | lines.add(lines.size() - 1, "}"); |
---|
807 | } |
---|
808 | } |
---|
809 | else { |
---|
810 | lines.add(task + " {}"); |
---|
811 | } |
---|
812 | } |
---|
813 | } |
---|
814 | |
---|
815 | /** |
---|
816 | * |
---|
817 | */ |
---|
818 | /*@SuppressWarnings("unchecked") |
---|
819 | private void getSelections(Delta delta, List<TaskPath> result) { |
---|
820 | TaskPath path1 = getCommonPath((List<TaskPath>) delta.getOriginal().getLines()); |
---|
821 | TaskPath path2 = getCommonPath((List<TaskPath>) delta.getRevised().getLines()); |
---|
822 | |
---|
823 | for (int i = 0; i < path1.size(); i++) { |
---|
824 | if (path1.getTask(i) instanceof ISelection) { |
---|
825 | System.out.println("found selection to ignore"); |
---|
826 | System.out.println(path1.subPath(0, i + 1)); |
---|
827 | result.add(path1.subPath(0, i + 1)); |
---|
828 | break; |
---|
829 | } |
---|
830 | } |
---|
831 | |
---|
832 | for (int i = 0; i < path2.size(); i++) { |
---|
833 | if (path2.getTask(i) instanceof ISelection) { |
---|
834 | System.out.println("found selection to ignore"); |
---|
835 | System.out.println(path2.subPath(0, i + 1)); |
---|
836 | result.add(path2.subPath(0, i + 1)); |
---|
837 | break; |
---|
838 | } |
---|
839 | } |
---|
840 | }*/ |
---|
841 | |
---|
842 | /** |
---|
843 | * |
---|
844 | */ |
---|
845 | @SuppressWarnings("unchecked") |
---|
846 | private void getPathsToRealIntersectingIterations(Delta delta, List<TaskPath> paths) { |
---|
847 | TaskPath path1 = getCommonPath((List<TaskPath>) delta.getOriginal().getLines()); |
---|
848 | TaskPath path2 = getCommonPath((List<TaskPath>) delta.getRevised().getLines()); |
---|
849 | |
---|
850 | // both paths denote those parent tasks that contain the delta. |
---|
851 | // But there may be parent tasks still contained in the path that are iterations and |
---|
852 | // that are disjoint with a parent in the other path. Those iterations need to be |
---|
853 | // considered, as otherwise a created selection would be against the associative law of |
---|
854 | // iterations. Hence, we search for the topmost iteration on both paths that is disjoint |
---|
855 | // with a parent node in the respective other path. |
---|
856 | |
---|
857 | for (int i = 0; i < path1.size(); i++) { |
---|
858 | TaskPath path1Prefix = path1.subPath(0, i + 1); |
---|
859 | int[] idxsPath1 = leftHandSideTraversal.getIndexesRootedBy(path1Prefix); |
---|
860 | |
---|
861 | // normalize the indexes to be 0 the index of the delta. Everything left of it |
---|
862 | // is smaller 0, everything right of it, larger. |
---|
863 | idxsPath1[0] -= delta.getOriginal().getPosition(); |
---|
864 | idxsPath1[1] -= delta.getOriginal().getPosition() + delta.getOriginal().size() - 1; |
---|
865 | |
---|
866 | for (int j = 0; j < path2.size(); j++) { |
---|
867 | TaskPath path2Prefix = path2.subPath(0, j + 1); |
---|
868 | int[] idxsPath2 = rightHandSideTraversal.getIndexesRootedBy(path2Prefix); |
---|
869 | |
---|
870 | // normalize the indexes to be 0 the index of the delta. Everything left of it |
---|
871 | // is smaller 0, everything right of it, larger. |
---|
872 | idxsPath2[0] -= delta.getRevised().getPosition(); |
---|
873 | idxsPath2[1] -= |
---|
874 | delta.getRevised().getPosition() + delta.getRevised().size() - 1; |
---|
875 | |
---|
876 | // now compare the indexes and check, if the sublists are real subsets of each |
---|
877 | // other. If not, they only have a real common subset but there is at least one |
---|
878 | // non shared element on both sides. If so, and one is an iteration, we |
---|
879 | // have to use it as elements to be selected |
---|
880 | if (((idxsPath1[0] < idxsPath2[0]) && (idxsPath1[1] < idxsPath2[1])) || |
---|
881 | ((idxsPath1[0] > idxsPath2[0]) && (idxsPath1[1] > idxsPath2[1]))) |
---|
882 | { |
---|
883 | if ((path1.get(i).getTask() instanceof IIteration) && |
---|
884 | (path2.get(j).getTask() instanceof IIteration)) |
---|
885 | { |
---|
886 | // System.out.println("found paths to real intersecting parents"); |
---|
887 | // int[] indexBuf = leftHandSideTraversal.getIndexesRootedBy(path1Prefix); |
---|
888 | // System.out.println(idxsPath1[0] + "(" + indexBuf[0] + ") " + idxsPath1[1] + |
---|
889 | // "(" + indexBuf[1] + ") " + path1Prefix); |
---|
890 | // indexBuf = rightHandSideTraversal.getIndexesRootedBy(path2Prefix); |
---|
891 | // System.out.println(idxsPath2[0] + "(" + indexBuf[0] + ") " + idxsPath2[1] + |
---|
892 | // "(" + indexBuf[1] + ") " + path2Prefix); |
---|
893 | |
---|
894 | paths.add(path1Prefix); |
---|
895 | paths.add(path2Prefix); |
---|
896 | return; |
---|
897 | } |
---|
898 | } |
---|
899 | } |
---|
900 | } |
---|
901 | } |
---|
902 | |
---|
903 | /** |
---|
904 | * |
---|
905 | */ |
---|
906 | private TaskPath getCommonPath(List<TaskPath> paths) { |
---|
907 | TaskPath commonPath; |
---|
908 | |
---|
909 | if (paths.size() > 0) { |
---|
910 | commonPath = new TaskPath(paths.get(0)); |
---|
911 | |
---|
912 | for (int i = 1; i < paths.size(); i++) { |
---|
913 | TaskPath comparePath = paths.get(i); |
---|
914 | for (int j = 0; (j < commonPath.size()) && (j < comparePath.size()); j++) { |
---|
915 | if (!commonPath.get(j).equals(comparePath.get(j))) { |
---|
916 | while (commonPath.size() > j) { |
---|
917 | commonPath.removeLast(); |
---|
918 | } |
---|
919 | break; |
---|
920 | } |
---|
921 | } |
---|
922 | } |
---|
923 | } |
---|
924 | else { |
---|
925 | commonPath = new TaskPath(); |
---|
926 | } |
---|
927 | |
---|
928 | return commonPath; |
---|
929 | } |
---|
930 | |
---|
931 | /** |
---|
932 | * |
---|
933 | */ |
---|
934 | private void getNotFullyInterleavingIteration(Delta delta, List<TaskPath> result) { |
---|
935 | getNotFullyInterleavingIterations(delta.getOriginal(), leftHandSideTraversal, result); |
---|
936 | getNotFullyInterleavingIterations(delta.getRevised(), rightHandSideTraversal, result); |
---|
937 | } |
---|
938 | |
---|
939 | /** |
---|
940 | * If a chunk has a minimum number of 2 entries and at least one of them belongs to an iteration |
---|
941 | * the does not cover the other and also expands to preceding or succeeding paths in the |
---|
942 | * traversal, we can no merge the situation. |
---|
943 | */ |
---|
944 | private void getNotFullyInterleavingIterations(Chunk chunk, |
---|
945 | TaskTraversal traversal, |
---|
946 | List<TaskPath> result) |
---|
947 | { |
---|
948 | @SuppressWarnings("unchecked") |
---|
949 | List<TaskPath> paths = (List<TaskPath>) chunk.getLines(); |
---|
950 | |
---|
951 | TaskPath commonPath = getCommonPath(paths); |
---|
952 | |
---|
953 | if (paths.size() > 1) { |
---|
954 | TaskPath firstPath = paths.get(0); |
---|
955 | TaskPath lastPath = paths.get(paths.size() - 1); |
---|
956 | |
---|
957 | for (int i = commonPath.size(); i < firstPath.size(); i++) { |
---|
958 | if (firstPath.get(i).getTask() instanceof IIteration) { |
---|
959 | // check, if the iteration covers things preceding the delta but not the whole |
---|
960 | // delta |
---|
961 | int[] indexes = traversal.getIndexesRootedBy(firstPath.subPath(0, i + 1)); |
---|
962 | |
---|
963 | if ((indexes[0] < chunk.getPosition()) && // starts before the delta |
---|
964 | (indexes[1] < (chunk.getPosition() + chunk.size() - 1))) // does not cover delta |
---|
965 | { |
---|
966 | result.add(firstPath.subPath(0, i + 1)); |
---|
967 | break; |
---|
968 | } |
---|
969 | } |
---|
970 | } |
---|
971 | |
---|
972 | for (int i = commonPath.size(); i < lastPath.size(); i++) { |
---|
973 | if (lastPath.get(i).getTask() instanceof IIteration) { |
---|
974 | // check, if the iteration covers things preceding the delta but not the whole |
---|
975 | // delta |
---|
976 | int[] indexes = traversal.getIndexesRootedBy(lastPath.subPath(0, i + 1)); |
---|
977 | |
---|
978 | if ((indexes[0] > chunk.getPosition()) && // starts in between the delta |
---|
979 | (indexes[1] >= (chunk.getPosition() + chunk.size()))) // ends after the delta |
---|
980 | { |
---|
981 | result.add(lastPath.subPath(0, i + 1)); |
---|
982 | break; |
---|
983 | } |
---|
984 | } |
---|
985 | } |
---|
986 | } |
---|
987 | } |
---|
988 | |
---|
989 | /** |
---|
990 | * |
---|
991 | */ |
---|
992 | private void getPathsToParentTasksFullyInsideDelta(Delta delta, List<TaskPath> result) { |
---|
993 | getPathsToParentTasksFullyInsideChunk(delta.getOriginal(), leftHandSideTraversal, result); |
---|
994 | getPathsToParentTasksFullyInsideChunk(delta.getRevised(), rightHandSideTraversal, result); |
---|
995 | } |
---|
996 | |
---|
997 | /** |
---|
998 | * If a chunk has a minimum number of 2 entries and at least one of them belongs to an iteration |
---|
999 | * the does not cover the other and also expands to preceding or succeeding paths in the |
---|
1000 | * traversal, we can no merge the situation. |
---|
1001 | */ |
---|
1002 | private void getPathsToParentTasksFullyInsideChunk(Chunk chunk, |
---|
1003 | TaskTraversal traversal, |
---|
1004 | List<TaskPath> result) |
---|
1005 | { |
---|
1006 | @SuppressWarnings("unchecked") |
---|
1007 | List<TaskPath> paths = (List<TaskPath>) chunk.getLines(); |
---|
1008 | |
---|
1009 | TaskPath commonPath = getCommonPath(paths); |
---|
1010 | |
---|
1011 | for (TaskPath path : paths) { |
---|
1012 | for (int i = commonPath.size(); i < path.size(); i++) { |
---|
1013 | if (!(path.getLast() instanceof IEventTask)) { |
---|
1014 | // check, if the parent task covers things fully inside the delta |
---|
1015 | int[] indexes = traversal.getIndexesRootedBy(path.subPath(0, i + 1)); |
---|
1016 | |
---|
1017 | if ((chunk.getPosition() <= indexes[0]) && // starts in the delta |
---|
1018 | (indexes[1] < (chunk.getPosition() + chunk.size()))) // ends in the delta |
---|
1019 | { |
---|
1020 | // System.out.println("found path to parent task lieing completely in the " + |
---|
1021 | // "delta: " + path.subPath(0, i + 1)); |
---|
1022 | result.add(path.subPath(0, i + 1)); |
---|
1023 | break; |
---|
1024 | } |
---|
1025 | } |
---|
1026 | } |
---|
1027 | } |
---|
1028 | } |
---|
1029 | |
---|
1030 | /** |
---|
1031 | * |
---|
1032 | */ |
---|
1033 | private void getParentOptionals(TaskPath taskPath, List<TaskPath> result) { |
---|
1034 | ITask task = taskPath.getLast(); |
---|
1035 | |
---|
1036 | if (task instanceof IOptional) { |
---|
1037 | result.add(new TaskPath(taskPath)); |
---|
1038 | } |
---|
1039 | else if (task instanceof ISequence) { |
---|
1040 | for (int i = 0; i < ((ISequence) task).getChildren().size(); i++) { |
---|
1041 | taskPath.add(((ISequence) task).getChildren().get(i), i); |
---|
1042 | getParentOptionals(taskPath, result); |
---|
1043 | taskPath.removeLast(); |
---|
1044 | } |
---|
1045 | } |
---|
1046 | else if (task instanceof ISelection) { |
---|
1047 | for (int i = 0; i < ((ISelection) task).getChildren().size(); i++) { |
---|
1048 | taskPath.add(((ISelection) task).getChildren().get(i), 0); |
---|
1049 | getParentOptionals(taskPath, result); |
---|
1050 | taskPath.removeLast(); |
---|
1051 | } |
---|
1052 | } |
---|
1053 | else if (task instanceof IIteration) { |
---|
1054 | taskPath.add(((IIteration) task).getMarkedTask(), 0); |
---|
1055 | getParentOptionals(taskPath, result); |
---|
1056 | taskPath.removeLast(); |
---|
1057 | } |
---|
1058 | } |
---|
1059 | |
---|
1060 | /** |
---|
1061 | * |
---|
1062 | */ |
---|
1063 | @SuppressWarnings("unchecked") |
---|
1064 | private int getDiffLevel(Patch patch, |
---|
1065 | TaskTraversal traversal1, |
---|
1066 | TaskTraversal traversal2) |
---|
1067 | { |
---|
1068 | int diffCount = 0; |
---|
1069 | int allCount = 0; |
---|
1070 | |
---|
1071 | for (Delta delta : patch.getDeltas()) { |
---|
1072 | for (TaskPath path : (List<TaskPath>) delta.getOriginal().getLines()) { |
---|
1073 | // inefficient actions are counted later. |
---|
1074 | if (!isInefficientAction(path.getLast())) { |
---|
1075 | diffCount += getDiffPenalty(path.getLast()); |
---|
1076 | } |
---|
1077 | } |
---|
1078 | for (TaskPath path : (List<TaskPath>) delta.getRevised().getLines()) { |
---|
1079 | // inefficient actions are counted later. |
---|
1080 | if (!isInefficientAction(path.getLast())) { |
---|
1081 | diffCount += getDiffPenalty(path.getLast()); |
---|
1082 | } |
---|
1083 | } |
---|
1084 | } |
---|
1085 | |
---|
1086 | //if (getPathsToRealIntersectingIterations().size() > 0) { |
---|
1087 | // add a penalty if intersecting iterations are present |
---|
1088 | //count += 10; |
---|
1089 | //} |
---|
1090 | |
---|
1091 | // add a penalty for inefficient actions which are equal as they have to be treated |
---|
1092 | // unequal, too. Otherwise, many scrolls, e.g., would pretend a high equality of tasks |
---|
1093 | // which contain only some non inefficient actions |
---|
1094 | for (TaskPath path : traversal1.getTraversalPaths()) { |
---|
1095 | if (isInefficientAction(path.getLast())) { |
---|
1096 | diffCount++; |
---|
1097 | allCount++; |
---|
1098 | } |
---|
1099 | else { |
---|
1100 | allCount += getDiffPenalty(path.getLast()); |
---|
1101 | } |
---|
1102 | } |
---|
1103 | |
---|
1104 | for (TaskPath path : traversal2.getTraversalPaths()) { |
---|
1105 | if (isInefficientAction(path.getLast())) { |
---|
1106 | diffCount++; |
---|
1107 | allCount++; |
---|
1108 | } |
---|
1109 | else { |
---|
1110 | allCount += getDiffPenalty(path.getLast()); |
---|
1111 | } |
---|
1112 | } |
---|
1113 | |
---|
1114 | if (allCount == 0) { |
---|
1115 | // this happens, if all actions are inefficient. Return the highest diff level |
---|
1116 | return 100; |
---|
1117 | } |
---|
1118 | else { |
---|
1119 | return (100 * diffCount) / allCount; |
---|
1120 | } |
---|
1121 | } |
---|
1122 | |
---|
1123 | /** |
---|
1124 | * |
---|
1125 | */ |
---|
1126 | private boolean isInefficientAction(ITask task) { |
---|
1127 | ITaskInstance inst = task.getInstances().iterator().next(); |
---|
1128 | |
---|
1129 | if ((inst instanceof IEventTaskInstance) && |
---|
1130 | (((IEventTaskInstance) inst).getEvent().getType() instanceof Scroll)) |
---|
1131 | { |
---|
1132 | return true; |
---|
1133 | } |
---|
1134 | else if (task instanceof IMarkingTemporalRelationship) { |
---|
1135 | return isInefficientAction(((IMarkingTemporalRelationship) task).getMarkedTask()); |
---|
1136 | } |
---|
1137 | else { |
---|
1138 | return false; |
---|
1139 | } |
---|
1140 | } |
---|
1141 | |
---|
1142 | |
---|
1143 | /** |
---|
1144 | * |
---|
1145 | */ |
---|
1146 | private int getDiffPenalty(ITask task) { |
---|
1147 | if (task instanceof IEventTask) { |
---|
1148 | return 1; |
---|
1149 | } |
---|
1150 | else if (task instanceof IMarkingTemporalRelationship) { |
---|
1151 | return getDiffPenalty(((IMarkingTemporalRelationship) task).getMarkedTask()); |
---|
1152 | } |
---|
1153 | else if (task instanceof IStructuringTemporalRelationship) { |
---|
1154 | int result = 0; |
---|
1155 | |
---|
1156 | for (ITask child : ((IStructuringTemporalRelationship) task).getChildren()) { |
---|
1157 | result += getDiffPenalty(child); |
---|
1158 | } |
---|
1159 | |
---|
1160 | if (task instanceof ISelection) { |
---|
1161 | result /= ((IStructuringTemporalRelationship) task).getChildren().size(); |
---|
1162 | } |
---|
1163 | |
---|
1164 | return result; |
---|
1165 | } |
---|
1166 | |
---|
1167 | throw new IllegalArgumentException("unknown type of task: " + task); |
---|
1168 | } |
---|
1169 | } |
---|