1 11 package org.eclipse.compare.structuremergeviewer; 12 13 import java.io.*; 14 import java.util.ArrayList ; 15 import java.util.HashMap ; 16 import java.util.HashSet ; 17 import java.util.Iterator ; 18 import java.util.List ; 19 import java.util.Map ; 20 import java.util.Set ; 21 import com.ibm.icu.text.MessageFormat; 22 23 import org.eclipse.jface.util.Assert; 24 25 import org.eclipse.core.runtime.CoreException; 26 import org.eclipse.core.runtime.IProgressMonitor; 27 import org.eclipse.core.runtime.OperationCanceledException; 28 29 import org.eclipse.compare.*; 30 import org.eclipse.compare.internal.Utilities; 31 32 33 59 public class Differencer { 60 61 65 public static final int NO_CHANGE= 0; 66 69 public static final int ADDITION= 1; 70 73 public static final int DELETION= 2; 74 77 public static final int CHANGE= 3; 78 79 82 public static final int CHANGE_TYPE_MASK= 3; 83 84 88 public static final int LEFT= 4; 89 90 93 public static final int RIGHT= 8; 94 95 99 public static final int CONFLICTING= 12; 100 101 104 public static final int DIRECTION_MASK= 12; 105 106 110 public static final int PSEUDO_CONFLICT= 16; 111 112 113 static class Node { 114 List fChildren; 115 int fCode; 116 Object fAncestor; 117 Object fLeft; 118 Object fRight; 119 120 Node() { 121 } 123 Node(Node parent, Object ancestor, Object left, Object right) { 124 parent.add(this); 125 fAncestor= ancestor; 126 fLeft= left; 127 fRight= right; 128 } 129 void add(Node child) { 130 if (fChildren == null) 131 fChildren= new ArrayList (); 132 fChildren.add(child); 133 } 134 Object visit(Differencer d, Object parent, int level) { 135 if (fCode == NO_CHANGE) 136 return null; 137 Object data= d.visit(parent, fCode, fAncestor, fLeft, fRight); 139 if (fChildren != null) { 140 Iterator i= fChildren.iterator(); 141 while (i.hasNext()) { 142 Node n= (Node) i.next(); 143 n.visit(d, data, level+1); 144 } 145 } 146 return data; 147 } 148 165 } 193 194 197 public Differencer() { 198 } 200 201 217 public Object findDifferences(boolean threeWay, IProgressMonitor pm, Object data, Object ancestor, Object left, Object right) { 218 219 Node root= new Node(); 220 221 int code= traverse(threeWay, root, pm, threeWay ? ancestor : null, left, right); 222 223 if (code != NO_CHANGE) { 224 List l= root.fChildren; 225 if (l.size() > 0) { 226 Node first= (Node)l.get(0); 227 return first.visit(this, data, 0); 228 } 229 } 230 return null; 231 } 232 233 236 private int traverse(boolean threeWay, Node parent, IProgressMonitor pm, Object ancestor, Object left, Object right) { 237 238 Object [] ancestorChildren= getChildren(ancestor); 239 Object [] rightChildren= getChildren(right); 240 Object [] leftChildren= getChildren(left); 241 242 int code= NO_CHANGE; 243 244 Node node= new Node(parent, ancestor, left, right); 245 246 boolean content= true; 248 if (((threeWay && ancestorChildren != null) || !threeWay) 249 && rightChildren != null && leftChildren != null) { 250 253 Set allSet= new HashSet (20); 254 Map ancestorSet= null; 255 Map rightSet= null; 256 Map leftSet= null; 257 258 if (ancestorChildren != null) { 259 ancestorSet= new HashMap (10); 260 for (int i= 0; i < ancestorChildren.length; i++) { 261 Object ancestorChild= ancestorChildren[i]; 262 ancestorSet.put(ancestorChild, ancestorChild); 263 allSet.add(ancestorChild); 264 } 265 } 266 267 if (rightChildren != null) { 268 rightSet= new HashMap (10); 269 for (int i= 0; i < rightChildren.length; i++) { 270 Object rightChild= rightChildren[i]; 271 rightSet.put(rightChild, rightChild); 272 allSet.add(rightChild); 273 } 274 } 275 276 if (leftChildren != null) { 277 leftSet= new HashMap (10); 278 for (int i= 0; i < leftChildren.length; i++) { 279 Object leftChild= leftChildren[i]; 280 leftSet.put(leftChild, leftChild); 281 allSet.add(leftChild); 282 } 283 } 284 285 Iterator e= allSet.iterator(); 286 while (e.hasNext()) { 287 Object keyChild= e.next(); 288 289 if (pm != null) { 290 291 if (pm.isCanceled()) 292 throw new OperationCanceledException(); 293 294 updateProgress(pm, keyChild); 295 } 296 297 Object ancestorChild= ancestorSet != null ? ancestorSet.get(keyChild) : null; 298 Object leftChild= leftSet != null ? leftSet.get(keyChild) : null; 299 Object rightChild= rightSet != null ? rightSet.get(keyChild) : null; 300 301 int c= traverse(threeWay, node, pm, ancestorChild, leftChild, rightChild); 302 303 if ((c & CHANGE_TYPE_MASK) != NO_CHANGE) { 304 code|= CHANGE; code|= (c & DIRECTION_MASK); content= false; 307 } 308 } 309 } 310 311 if (content) code= compare(threeWay, ancestor, left, right); 313 314 node.fCode= code; 315 316 return code; 317 } 318 319 337 protected Object visit(Object data, int result, Object ancestor, Object left, Object right) { 338 return new DiffNode((IDiffContainer) data, result, (ITypedElement)ancestor, (ITypedElement)left, (ITypedElement)right); 339 } 340 341 345 private int compare(boolean threeway, Object ancestor, Object left, Object right) { 346 347 int description= NO_CHANGE; 348 349 if (threeway) { 350 if (ancestor == null) { 351 if (left == null) { 352 if (right == null) { 353 Assert.isTrue(false); 354 } else { 356 description= RIGHT | ADDITION; 357 } 358 } else { 359 if (right == null) { 360 description= LEFT | ADDITION; 361 } else { 362 description= CONFLICTING | ADDITION; 363 if (contentsEqual(left, right)) 364 description|= PSEUDO_CONFLICT; 365 } 366 } 367 } else { 368 if (left == null) { 369 if (right == null) { 370 description= CONFLICTING | DELETION | PSEUDO_CONFLICT; 371 } else { 372 if (contentsEqual(ancestor, right)) 373 description= LEFT | DELETION; 374 else 375 description= CONFLICTING | CHANGE; 376 } 377 } else { 378 if (right == null) { 379 if (contentsEqual(ancestor, left)) 380 description= RIGHT | DELETION; 381 else 382 description= CONFLICTING | CHANGE; 383 } else { 384 boolean ay= contentsEqual(ancestor, left); 385 boolean am= contentsEqual(ancestor, right); 386 387 if (ay && am) { 388 } else if (ay && !am) { 390 description= RIGHT | CHANGE; 391 } else if (!ay && am) { 392 description= LEFT | CHANGE; 393 } else { 394 description= CONFLICTING | CHANGE; 395 if (contentsEqual(left, right)) 396 description|= PSEUDO_CONFLICT; 397 } 398 } 399 } 400 } 401 } else { if (left == null) { 403 if (right == null) { 404 Assert.isTrue(false); 405 } else { 407 description= ADDITION; 408 } 409 } else { 410 if (right == null) { 411 description= DELETION; 412 } else { 413 if (! contentsEqual(left, right)) 414 description= CHANGE; 415 } 416 } 417 } 418 419 return description; 420 } 421 422 435 protected boolean contentsEqual(Object input1, Object input2) { 436 437 if (input1 == input2) 438 return true; 439 440 InputStream is1= getStream(input1); 441 InputStream is2= getStream(input2); 442 443 if (is1 == null && is2 == null) return true; 445 446 try { 447 if (is1 == null || is2 == null) return false; 449 450 while (true) { 451 int c1= is1.read(); 452 int c2= is2.read(); 453 if (c1 == -1 && c2 == -1) 454 return true; 455 if (c1 != c2) 456 break; 457 458 } 459 } catch (IOException ex) { 460 } finally { 462 if (is1 != null) { 463 try { 464 is1.close(); 465 } catch(IOException ex) { 466 } 468 } 469 if (is2 != null) { 470 try { 471 is2.close(); 472 } catch(IOException ex) { 473 } 475 } 476 } 477 return false; 478 } 479 480 485 private InputStream getStream(Object o) { 486 if (o instanceof IStreamContentAccessor) { 487 try { 488 return ((IStreamContentAccessor)o).getContents(); 489 } catch(CoreException ex) { 490 } 492 } 493 return null; 494 } 495 496 508 protected Object [] getChildren(Object input) { 509 if (input instanceof IStructureComparator) 510 return ((IStructureComparator)input).getChildren(); 511 return null; 512 } 513 514 524 protected void updateProgress(IProgressMonitor progressMonitor, Object node) { 525 if (node instanceof ITypedElement) { 526 String name= ((ITypedElement)node).getName(); 527 String fmt= Utilities.getString("Differencer.progressFormat"); String msg= MessageFormat.format(fmt, new String [] { name }); 529 progressMonitor.subTask(msg); 530 } 532 } 533 } 534 535 | Popular Tags |