1 19 20 package org.netbeans.modules.diff.builtin.visualizer; 21 22 import java.awt.Component ; 23 import java.io.IOException ; 24 import java.io.InputStream ; 25 import java.io.Reader ; 26 import java.io.BufferedReader ; 27 import java.io.ByteArrayInputStream ; 28 import java.io.Serializable ; 29 import org.openide.windows.CloneableOpenSupport; 30 31 import org.openide.util.NbBundle; 32 33 import org.netbeans.api.diff.Difference; 34 import org.netbeans.spi.diff.DiffVisualizer; 35 36 import org.netbeans.modules.diff.builtin.DiffPresenter; 37 38 43 public class TextDiffVisualizer extends DiffVisualizer implements Serializable { 44 45 private boolean contextMode = true; 46 private int contextNumLines = 3; 47 48 static final long serialVersionUID =-2481513747957146261L; 49 50 public TextDiffVisualizer() { 51 } 52 53 56 public String getDisplayName() { 57 return NbBundle.getMessage(TextDiffVisualizer.class, "TextDiffVisualizer.displayName"); 58 } 59 60 63 public String getShortDescription() { 64 return NbBundle.getMessage(TextDiffVisualizer.class, "TextDiffVisualizer.shortDescription"); 65 } 66 67 70 public boolean isContextMode() { 71 return contextMode; 72 } 73 74 77 public void setContextMode(boolean contextMode) { 78 this.contextMode = contextMode; 79 } 80 81 84 public int getContextNumLines() { 85 return contextNumLines; 86 } 87 88 91 public void setContextNumLines(int contextNumLines) { 92 this.contextNumLines = contextNumLines; 93 } 94 95 104 105 120 public Component createView(Difference[] diffs, String name1, String title1, Reader r1, 121 String name2, String title2, Reader r2, String MIMEType) throws IOException { 122 130 TextDiffInfo diff = new TextDiffInfo(name1, name2, title1, title2, r1, r2, diffs); 131 diff.setContextMode(contextMode, contextNumLines); 132 return ((TextDiffEditorSupport) diff.getOpenSupport()).createCloneableTopComponentForMe(); 133 } 134 135 static InputStream differenceToLineDiffText(Difference[] diffs) { 136 StringBuffer content = new StringBuffer (); 137 int n1, n2, n3, n4; 138 for (int i = 0; i < diffs.length; i++) { 139 Difference diff = diffs[i]; 140 switch (diff.getType()) { 141 case Difference.ADD: 142 n3 = diff.getSecondStart(); 143 n4 = diff.getSecondEnd(); 144 if (n3 == n4) { 145 content.append(diff.getFirstStart()+"a"+n3+"\n"); 146 } else { 147 content.append(diff.getFirstStart()+"a"+n3+","+n4+"\n"); 148 } 149 appendText(content, "> ", diff.getSecondText()); 150 break; 151 case Difference.DELETE: 152 n1 = diff.getFirstStart(); 153 n2 = diff.getFirstEnd(); 154 if (n1 == n2) { 155 content.append(n1+"d"+diff.getSecondStart()+"\n"); 156 } else { 157 content.append(n1+","+n2+"d"+diff.getSecondStart()+"\n"); 158 } 159 appendText(content, "< ", diff.getFirstText()); 160 break; 161 case Difference.CHANGE: 162 n1 = diff.getFirstStart(); 163 n2 = diff.getFirstEnd(); 164 n3 = diff.getSecondStart(); 165 n4 = diff.getSecondEnd(); 166 if (n1 == n2 && n3 == n4) { 167 content.append(n1+"c"+n3+"\n"); 168 } else if (n1 == n2) { 169 content.append(n1+"c"+n3+","+n4+"\n"); 170 } else if (n3 == n4) { 171 content.append(n1+","+n2+"c"+n3+"\n"); 172 } else { 173 content.append(n1+","+n2+"c"+n3+","+n4+"\n"); 174 } 175 appendText(content, "< ", diff.getFirstText()); 176 content.append("---\n"); 177 appendText(content, "> ", diff.getSecondText()); 178 break; 179 } 180 } 181 return new ByteArrayInputStream (content.toString().getBytes()); 182 } 183 184 private static void appendText(StringBuffer buff, String prefix, String text) { 185 if (text == null) return ; 186 int startLine = 0; 187 do { 188 int endLine = text.indexOf('\n', startLine); 189 if (endLine < 0) endLine = text.length(); 190 buff.append(prefix + text.substring(startLine, endLine) + "\n"); 191 startLine = endLine + 1; 192 } while (startLine < text.length()); 193 } 194 195 private static final String CONTEXT_MARK1B = "*** "; 196 private static final String CONTEXT_MARK1E = " ****\n"; 197 private static final String CONTEXT_MARK2B = "--- "; 198 private static final String CONTEXT_MARK2E = " ----\n"; 199 private static final String CONTEXT_MARK_DELIMETER = ","; 200 private static final String DIFFERENCE_DELIMETER = "***************\n"; 201 private static final String LINE_PREP = " "; 202 private static final String LINE_PREP_ADD = "+ "; 203 private static final String LINE_PREP_REMOVE = "- "; 204 private static final String LINE_PREP_CHANGE = "! "; 205 206 209 public static InputStream differenceToContextDiffText(TextDiffInfo diffInfo) throws IOException { 210 StringBuffer content = new StringBuffer (); 211 content.append(CONTEXT_MARK1B); 212 content.append(diffInfo.getName1()); 213 content.append("\n"); 214 content.append(CONTEXT_MARK2B); 215 content.append(diffInfo.getName2()); 216 content.append("\n"); 217 final int contextNumLines = diffInfo.getContextNumLines(); 218 Difference[] diffs = diffInfo.getDifferences(); 219 BufferedReader br1 = new BufferedReader (diffInfo.createFirstReader()); 220 BufferedReader br2 = new BufferedReader (diffInfo.createSecondReader()); 221 int line1 = 1; int line2 = 1; for (int i = 0; i < diffs.length; i++) { 224 225 content.append(DIFFERENCE_DELIMETER); 226 227 int[] cr = getContextRange(diffs, i, contextNumLines); 228 229 int begin = diffs[i].getFirstStart() - contextNumLines; 230 if (diffs[i].getType() == Difference.ADD) begin++; 231 if (begin < 1) begin = 1; 232 StringBuffer context = new StringBuffer (); 233 line1 = dumpContext(0, diffs, i, cr[0], context, contextNumLines, br1, line1); 234 int end1 = line1 <= cr[1] ? 235 line1 + contextNumLines : 236 cr[1]; 237 if (line1 <= cr[1] && i == diffs.length -1) { 238 int buffer = contextNumLines; 240 int existingLines = 0; 241 while (buffer-- > 0) { 242 String l = br1.readLine(); 243 if (l == null) { 244 break; 245 } 246 existingLines++; 247 } 248 if (existingLines<contextNumLines) { 249 end1 = line1 + existingLines - 1; 250 } 251 } 252 content.append(CONTEXT_MARK1B); 253 content.append(begin); 254 content.append(CONTEXT_MARK_DELIMETER); 255 content.append(end1); 256 content.append(CONTEXT_MARK1E); 257 content.append(context); 258 259 begin = diffs[i].getSecondStart() - contextNumLines; 260 if (diffs[i].getType() == Difference.DELETE) begin++; 261 if (begin < 1) begin = 1; 262 context = new StringBuffer (); 263 line2 = dumpContext(1, diffs, i, cr[0], context, contextNumLines, br2, line2); 264 int end2 = line2 <= cr[2] ? 265 line2 + contextNumLines : 266 cr[2]; 267 if (line2 <= cr[2] && i == diffs.length -1) { 268 int buffer = contextNumLines; 270 int existingLines = 0; 271 while (buffer-- > 0) { 272 String l = br2.readLine(); 273 if (l == null) { 274 break; 275 } 276 existingLines++; 277 } 278 if (existingLines<contextNumLines) { 279 end2 = line2 + existingLines - 1; 280 } 281 } 282 content.append(CONTEXT_MARK2B); 283 content.append(begin); 284 content.append(CONTEXT_MARK_DELIMETER); 285 content.append(end2); 286 content.append(CONTEXT_MARK2E); 287 content.append(context); 288 289 i = cr[0]; 290 } 297 return new ByteArrayInputStream (content.toString().getBytes("utf8")); } 299 300 private static int[] getContextRange(Difference[] diffs, int i, 301 int contextNumLines) { 302 int line1 = diffs[i].getFirstStart(); 303 int line2 = diffs[i].getSecondStart(); 304 for ( ; i < diffs.length; i++) { 305 Difference diff = diffs[i]; 306 if (line1 + 2*contextNumLines < diff.getFirstStart() && 307 line2 + 2*contextNumLines < diff.getSecondStart()) break; 308 line1 = diff.getFirstStart(); 309 line2 = diff.getSecondStart(); 310 int l1 = Math.max(0, diff.getFirstEnd() - diff.getFirstStart()); 311 int l2 = Math.max(0, diff.getSecondEnd() - diff.getSecondStart()); 312 line1 += l1; 313 line2 += l2; 314 } 315 return new int[] { i - 1, line1 + contextNumLines, line2 + contextNumLines }; 316 } 317 318 private static int dumpContext(int which, Difference[] diffs, int i, int j, 319 StringBuffer content, final int contextNumLines, BufferedReader br, int line) 320 throws IOException { 321 322 int startLine; 323 if (which == 0) { 324 startLine = diffs[i].getFirstStart() - contextNumLines; 325 if (diffs[i].getType() == Difference.ADD) startLine++; 326 } else { 327 startLine = diffs[i].getSecondStart() - contextNumLines; 328 if (diffs[i].getType() == Difference.DELETE) startLine++; 329 } 330 for ( ; line < startLine; line++) br.readLine(); 331 int position = content.length(); 332 boolean isChange = false; 333 for ( ; i <= j; i++) { 334 Difference diff = diffs[i]; 335 if (which == 0) startLine = diff.getFirstStart(); 336 else startLine = diff.getSecondStart(); 337 for ( ; line < startLine; line++) { 338 content.append(LINE_PREP); 339 content.append(br.readLine()); 340 content.append("\n"); 341 } 342 int length = 0; 343 String prep = null; 344 switch (diffs[i].getType()) { 345 case Difference.ADD: 346 if (which == 1) { 347 prep = LINE_PREP_ADD; 348 length = diff.getSecondEnd() - diff.getSecondStart() + 1; 349 } 350 break; 351 case Difference.DELETE: 352 if (which == 0) { 353 prep = LINE_PREP_REMOVE; 354 length = diff.getFirstEnd() - diff.getFirstStart() + 1; 355 } 356 break; 357 case Difference.CHANGE: 358 prep = LINE_PREP_CHANGE; 359 if (which == 0) { 360 length = diff.getFirstEnd() - diff.getFirstStart() + 1; 361 } else { 362 length = diff.getSecondEnd() - diff.getSecondStart() + 1; 363 } 364 break; 365 } 366 if (prep != null) { 367 isChange = true; 368 for (int k = 0; k < length; k++, line++) { 369 content.append(prep); 370 content.append(br.readLine()); 371 content.append("\n"); 372 } 373 } 374 } 375 if (!isChange) { 376 content.delete(position, content.length()); 377 } else { 378 for (int k = 0; k < contextNumLines; k++, line++) { 379 String lineStr = br.readLine(); 380 if (lineStr == null) break; 381 content.append(LINE_PREP); 382 content.append(lineStr); 383 content.append("\n"); 384 } 385 } 386 return line; 387 } 388 389 public static class TextDiffInfo extends DiffPresenter.Info { 390 391 private Reader r1; 392 private Reader r2; 393 private Difference[] diffs; 394 private CloneableOpenSupport openSupport; 395 private boolean contextMode; 396 private int contextNumLines; 397 398 public TextDiffInfo(String name1, String name2, String title1, String title2, 399 Reader r1, Reader r2, Difference[] diffs) { 400 super(name1, name2, title1, title2, null, false, false); 401 this.r1 = r1; 402 this.r2 = r2; 403 this.diffs = diffs; 404 } 405 406 public String getName() { 407 String componentName = getName1(); 408 String name2 = getName2(); 409 if (name2 != null && name2.length() > 0) componentName += " <> "+name2; 410 return componentName; 411 } 412 413 public String getTitle() { 414 return getTitle1() + " <> " + getTitle2(); 415 } 416 417 public Reader createFirstReader() { 418 return r1; 419 } 420 421 public Reader createSecondReader() { 422 return r2; 423 } 424 425 public Difference[] getDifferences() { 426 return diffs; 427 } 428 429 public CloneableOpenSupport getOpenSupport() { 430 if (openSupport == null) { 431 openSupport = new TextDiffEditorSupport(this); 432 } 433 return openSupport; 434 } 435 436 439 public void setContextMode(boolean contextMode, int contextNumLines) { 440 this.contextMode = contextMode; 441 this.contextNumLines = contextNumLines; 442 } 443 444 447 public boolean isContextMode() { 448 return contextMode; 449 } 450 451 public int getContextNumLines() { 452 return contextNumLines; 453 } 454 455 } 456 } 457 | Popular Tags |