KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > diff > builtin > visualizer > DiffComponent


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.diff.builtin.visualizer;
21
22 import java.util.*;
23 import java.io.*;
24 import javax.swing.*;
25 import javax.swing.text.*;
26 import java.awt.BorderLayout JavaDoc;
27
28 import org.openide.util.HelpCtx;
29 import org.openide.windows.*;
30
31 import org.netbeans.api.diff.Difference;
32 import org.netbeans.modules.diff.builtin.DiffPresenter;
33
34 //import org.netbeans.modules.vcscore.util.Debug;
35
//import org.netbeans.modules.vcscore.util.TopComponentCloseListener;
36

37 /**
38  * This class displays two editor panes with two files and marks the differences
39  * by a different color.
40  *
41  * @author Martin Entlicher
42  */

43 public class DiffComponent extends org.openide.windows.TopComponent {
44
45     public static final java.awt.Color JavaDoc COLOR_MISSING = new java.awt.Color JavaDoc(255, 160, 180);
46     public static final java.awt.Color JavaDoc COLOR_ADDED = new java.awt.Color JavaDoc(180, 255, 180);
47     public static final java.awt.Color JavaDoc COLOR_CHANGED = new java.awt.Color JavaDoc(160, 200, 255);
48     
49     //private AbstractDiff diff = null;
50
private Difference[] diffs = null;
51     /** The shift of differences */
52     private int[][] diffShifts;
53     private DiffPanel diffPanel = null;
54     
55     private java.awt.Color JavaDoc colorMissing = COLOR_MISSING;
56     private java.awt.Color JavaDoc colorAdded = COLOR_ADDED;
57     private java.awt.Color JavaDoc colorChanged = COLOR_CHANGED;
58     
59     //private ArrayList closeListeners = new ArrayList();
60
private int currentDiffLine = -1;
61     
62     /**
63      * Used for deserialization.
64      */

65     private boolean diffSetSuccess = true;
66
67     static final long serialVersionUID =3683458237532937983L;
68     
69     /**
70      * An empty constructor needed by deserialization process.
71      */

72     public DiffComponent() {
73         putClientProperty("PersistenceType", "Never");
74     }
75     
76     /** Creates new DiffComponent from list of Difference objects */
77     public DiffComponent(final Difference[] diffs, final String JavaDoc mainTitle, final String JavaDoc mimeType,
78                          final String JavaDoc sourceName1, final String JavaDoc sourceName2,
79                          final String JavaDoc title1, final String JavaDoc title2,
80                          final Reader r1, final Reader r2) {
81         this(diffs, mainTitle, mimeType, sourceName1, sourceName2, title1, title2,
82              r1, r2, null);
83     }
84     
85     /** Creates new DiffComponent from list of Difference objects */
86     public DiffComponent(final Difference[] diffs, final String JavaDoc mainTitle, final String JavaDoc mimeType,
87                          final String JavaDoc sourceName1, final String JavaDoc sourceName2,
88                          final String JavaDoc title1, final String JavaDoc title2,
89                          final Reader r1, final Reader r2, java.awt.Color JavaDoc[] colors) {
90         this.diffs = diffs;
91         diffShifts = new int[diffs.length][2];
92         setLayout(new BorderLayout JavaDoc());
93         diffPanel = new DiffPanel();
94         putClientProperty(DiffPresenter.PROP_TOOLBAR, diffPanel.getClientProperty(DiffPresenter.PROP_TOOLBAR));
95         diffPanel.addPrevLineButtonListener(new java.awt.event.ActionListener JavaDoc() {
96             public void actionPerformed(java.awt.event.ActionEvent JavaDoc evt) {
97                 if (diffs.length == 0) return ;
98                 currentDiffLine--;
99                 if (currentDiffLine < 0) currentDiffLine = diffs.length - 1;
100                 showCurrentLine();
101             }
102         });
103         diffPanel.addNextLineButtonListener(new java.awt.event.ActionListener JavaDoc() {
104             public void actionPerformed(java.awt.event.ActionEvent JavaDoc evt) {
105                 if (diffs.length == 0) return ;
106                 currentDiffLine++;
107                 if (currentDiffLine >= diffs.length) currentDiffLine = 0;
108                 showCurrentLine();
109             }
110         });
111         add(diffPanel, BorderLayout.CENTER);
112         
113         if (colors != null && colors.length >= 3) {
114             colorMissing = colors[0];
115             colorAdded = colors[1];
116             colorChanged = colors[2];
117         }
118 // initComponents ();
119
//setTitle(org.openide.util.NbBundle.getBundle(DiffComponent.class).getString("DiffComponent.title"));
120
if (mainTitle == null) {
121             setName(org.openide.util.NbBundle.getBundle(DiffComponent.class).getString("DiffComponent.title"));
122         } else {
123             setName(mainTitle);
124         }
125         setIcon(org.openide.util.Utilities.loadImage("org/netbeans/modules/diff/diffSettingsIcon.gif", true));
126         initContent(mimeType, sourceName1, sourceName2, title1, title2, r1, r2);
127         //HelpCtx.setHelpIDString (getRootPane (), DiffComponent.class.getName ());
128
putClientProperty("PersistenceType", "Never");
129     }
130     
131     public HelpCtx getHelpCtx() {
132         return new HelpCtx(DiffComponent.class);
133     }
134
135
136
137     private void showCurrentLine() {
138         if (currentDiffLine >= diffs.length) return;
139         Difference diff = diffs[currentDiffLine];
140         int line = diff.getFirstStart() + diffShifts[currentDiffLine][0];
141         if (diff.getType() == Difference.ADD) line++;
142         int lf1 = diff.getFirstEnd() - diff.getFirstStart() + 1;
143         int lf2 = diff.getSecondEnd() - diff.getSecondStart() + 1;
144         int length = Math.max(lf1, lf2);
145         diffPanel.setCurrentLine(line, length);
146     }
147     
148     private void initContent(String JavaDoc mimeType, String JavaDoc sourceName1, String JavaDoc sourceName2,
149                              String JavaDoc title1, String JavaDoc title2, Reader r1, Reader r2) {
150         setMimeType1(mimeType);
151         setMimeType2(mimeType);
152         try {
153             setSource1(r1);
154             setSource2(r2);
155         } catch (IOException ioex) {
156             org.openide.ErrorManager.getDefault().notify(ioex);
157         }
158         setSource1Title(title1);
159         setSource2Title(title2);
160         insertEmptyLines(true);
161         setDiffHighlight(true);
162         insertEmptyLinesNotReported();
163     }
164
165     @Deprecated JavaDoc
166     public void open(Workspace workspace) {
167         super.open(workspace);
168         diffPanel.open();
169         if (currentDiffLine < 0) {
170             currentDiffLine = 0;
171             showCurrentLine();
172         }
173     }
174     
175     /**
176      * Transfer the focus to the diff panel.
177      */

178     @Deprecated JavaDoc
179     public void requestFocus() {
180         super.requestFocus();
181         diffPanel.requestFocus();
182     }
183     
184     /**
185      * Transfer the focus to the diff panel.
186      */

187     @Deprecated JavaDoc
188     public boolean requestFocusInWindow() {
189         super.requestFocusInWindow();
190         return diffPanel.requestFocusInWindow();
191     }
192     
193     public void addNotify() {
194         super.addNotify();
195         if (currentDiffLine < 0) {
196             javax.swing.SwingUtilities.invokeLater(new Runnable JavaDoc() {
197                 public void run() {
198                     diffPanel.open();
199                     javax.swing.SwingUtilities.invokeLater(new Runnable JavaDoc() {
200                         public void run() {
201                             java.awt.Toolkit.getDefaultToolkit().sync();
202                             javax.swing.SwingUtilities.invokeLater(new Runnable JavaDoc() {
203                                 public void run() {
204                                     if (currentDiffLine < 0) {
205                                         currentDiffLine = 0;
206                                         showCurrentLine();
207                                     }
208                                 }
209                             });
210                         }
211                     });
212                 }
213             });
214         }
215     }
216     
217     /**
218      * Override for clean up reasons.
219      * Will be moved to the appropriate method when will be made.
220      */

221     @Deprecated JavaDoc
222     public boolean canClose(Workspace workspace, boolean last) {
223         boolean can = super.canClose(workspace, last);
224         if (last && can) {
225             exitForm(null);
226         }
227         return can;
228     }
229     /*
230     public void removeNotify() {
231         System.out.println("removeNotify() called");
232         exitForm(null);
233         super.removeNotify();
234     }
235      */

236     
237     public void setSource1(Reader r) throws IOException {
238         diffPanel.setSource1(r);
239     }
240     
241     public void setSource2(Reader r) throws IOException {
242         diffPanel.setSource2(r);
243     }
244     
245     public void setSource1Title(String JavaDoc title) {
246         diffPanel.setSource1Title(title);
247     }
248     
249     public void setSource2Title(String JavaDoc title) {
250         diffPanel.setSource2Title(title);
251     }
252     
253     public void setMimeType1(String JavaDoc mime) {
254         diffPanel.setMimeType1(mime);
255     }
256     
257     public void setMimeType2(String JavaDoc mime) {
258         diffPanel.setMimeType2(mime);
259     }
260     
261     public void setDocument1(Document doc) {
262         diffPanel.setDocument1(doc);
263     }
264     
265     public void setDocument2(Document doc) {
266         diffPanel.setDocument2(doc);
267     }
268     
269     public void unhighlightAll() {
270         diffPanel.unhighlightAll();
271     }
272     
273     public void highlightRegion1(int line1, int line2, java.awt.Color JavaDoc color) {
274         //D.deb("Highlight region 1"); // NOI18N
275
diffPanel.highlightRegion1(line1, line2, color);
276     }
277     
278     public void highlightRegion2(int line1, int line2, java.awt.Color JavaDoc color) {
279         //D.deb("Highlight region 2"); // NOI18N
280
diffPanel.highlightRegion2(line1, line2, color);
281     }
282     
283     public void addEmptyLines1(int line, int numLines) {
284         diffPanel.addEmptyLines1(line, numLines);
285     }
286     
287     public void addEmptyLines2(int line, int numLines) {
288         diffPanel.addEmptyLines2(line, numLines);
289     }
290         
291     public void writeExternal(ObjectOutput out) throws IOException {
292         super.writeExternal(out);
293         //try {
294
out.writeObject(diffs);
295         /*
296         } catch (IOException exc) {
297             System.out.println("exc = "+exc);
298             exc.printStackTrace();
299             throw exc;
300         }
301          */

302     }
303     
304     private void insertEmptyLines(boolean updateActionLines) {
305         int n = diffs.length;
306         //int ins1 = 0;
307
//int ins2 = 0;
308
//D.deb("insertEmptyLines():"); // NOI18N
309
for(int i = 0; i < n; i++) {
310             Difference action = diffs[i];
311             int n1 = action.getFirstStart() + diffShifts[i][0];
312             int n2 = action.getFirstEnd() + diffShifts[i][0];
313             int n3 = action.getSecondStart() + diffShifts[i][1];
314             int n4 = action.getSecondEnd() + diffShifts[i][1];
315             //System.out.println("Action = "+action);
316
//System.out.println("ins1 = "+diffShifts[i][0]+", ins2 = "+diffShifts[i][1]);
317
if (updateActionLines && i < n - 1) {
318                 diffShifts[i + 1][0] = diffShifts[i][0];
319                 diffShifts[i + 1][1] = diffShifts[i][1];
320             }
321             switch (action.getType()) {
322                 case Difference.DELETE:
323                     addEmptyLines2(n3, n2 - n1 + 1);
324                     if (updateActionLines && i < n - 1) {
325                         diffShifts[i+1][1] += n2 - n1 + 1;
326                     }
327                     //ins2 += n2 - n1 + 1;
328
break;
329                 case Difference.ADD:
330                     addEmptyLines1(n1, n4 - n3 + 1);
331                     if (updateActionLines && i < n - 1) {
332                         diffShifts[i+1][0] += n4 - n3 + 1;
333                     }
334                     //ins1 += n4 - n3 + 1;
335
break;
336                 case Difference.CHANGE:
337                     int r1 = n2 - n1;
338                     int r2 = n4 - n3;
339                     if (r1 < r2) {
340                         addEmptyLines1(n2, r2 - r1);
341                         if (updateActionLines && i < n - 1) {
342                             diffShifts[i+1][0] += r2 - r1;
343                         }
344                         //ins1 += r2 - r1;
345
} else if (r1 > r2) {
346                         addEmptyLines2(n4, r1 - r2);
347                         if (updateActionLines && i < n - 1) {
348                             diffShifts[i+1][1] += r1 - r2;
349                         }
350                         //ins2 += r1 - r2;
351
}
352                     break;
353             }
354         }
355     }
356     
357     private void setDiffHighlight(boolean set) {
358         int n = diffs.length;
359         //D.deb("Num Actions = "+n); // NOI18N
360
for(int i = 0; i < n; i++) {
361             Difference action = diffs[i];
362             int n1 = action.getFirstStart() + diffShifts[i][0];
363             int n2 = action.getFirstEnd() + diffShifts[i][0];
364             int n3 = action.getSecondStart() + diffShifts[i][1];
365             int n4 = action.getSecondEnd() + diffShifts[i][1];
366             //D.deb("Action: "+action.getAction()+": ("+n1+","+n2+","+n3+","+n4+")"); // NOI18N
367
switch (action.getType()) {
368             case Difference.DELETE:
369                 if (set) highlightRegion1(n1, n2, colorMissing);
370                 else highlightRegion1(n1, n2, java.awt.Color.white);
371                 break;
372             case Difference.ADD:
373                 if (set) highlightRegion2(n3, n4, colorAdded);
374                 else highlightRegion2(n3, n4, java.awt.Color.white);
375                 break;
376             case Difference.CHANGE:
377                 if (set) {
378                     highlightRegion1(n1, n2, colorChanged);
379                     highlightRegion2(n3, n4, colorChanged);
380                 } else {
381                     highlightRegion1(n1, n2, java.awt.Color.white);
382                     highlightRegion2(n3, n4, java.awt.Color.white);
383                 }
384                 break;
385             }
386         }
387     }
388     
389     /**
390      * Read one line from the given text, from the given position. It returns
391      * the end position of this line and the beginning of the next one.
392      * @param begin Contains just one value - IN: the beginning of the line to read.
393      * OUT: the start of the next line.
394      * @param end Contains just one value - OUT: the end of the line.
395      * @param text The text to read.
396      * @return The line.
397      */

398     private static String JavaDoc readLine(int[] begin, int[] end, String JavaDoc text) {
399         int n = text.length();
400         for (int i = begin[0]; i < n; i++) {
401             char c = text.charAt(i);
402             if (c == '\n' || c == '\r') {
403                 end[0] = i;
404                 break;
405             }
406         }
407         if (end[0] < begin[0]) end[0] = n;
408         String JavaDoc line = text.substring(begin[0], end[0]);
409         begin[0] = end[0] + 1;
410         if (begin[0] < n && text.charAt(end[0]) == '\r' && text.charAt(begin[0]) == '\n') begin[0]++;
411         return line;
412     }
413     
414     /**
415      * Find the first diff, that is on or below the given line number.
416      * @return The index of the desired difference in the supplied array or
417      * a value, that is bigger then the array size if such a diff does
418      * not exist.
419      */

420     private static int findDiffForLine(int lineNumber, int diffIndex, Difference[] diffs, int[][] diffShifts) {
421         while (diffIndex < diffs.length) {
422             if ((diffs[diffIndex].getFirstEnd() + diffShifts[diffIndex][0]) >= lineNumber ||
423                 (diffs[diffIndex].getSecondEnd() + diffShifts[diffIndex][1]) >= lineNumber) break;
424             diffIndex++;
425         }
426         return diffIndex;
427     }
428     
429     /**
430      * Find out whether the line lies in the difference.
431      * @param lineNumber The number of the line.
432      * @param diff The difference
433      * @param diffShifts The shifts of the difference in the current document
434      * @return true if the line lies in the difference, false if does not.
435      */

436     private static boolean isLineInDiff(int lineNumber, Difference diff, int[] diffShifts) {
437         int l1 = diff.getFirstStart() + diffShifts[0];
438         int l2 = diff.getFirstEnd() + diffShifts[0];
439         int l3 = diff.getSecondStart() + diffShifts[1];
440         int l4 = diff.getSecondEnd() + diffShifts[1];
441         return (l1 <= lineNumber && ((l2 >= l1) ? (l2 >= lineNumber) : false)) ||
442                (l3 <= lineNumber && ((l4 >= l3) ? (l4 >= lineNumber) : false));
443     }
444     
445     private static int numEmptyLines(int beginLine, String JavaDoc text, int endLine) {
446         if (endLine >= 0 && endLine <= beginLine) return 0;
447         int numLines = 0;
448         int[] begin = { beginLine };
449         int[] end = { 0 };
450         do {
451             String JavaDoc line = readLine(begin, end, text);
452             if (line.trim().length() > 0) break;
453             numLines++;
454         } while ((endLine < 0 || beginLine + numLines < endLine) && begin[0] < text.length());
455         return numLines;
456     }
457     
458     /**
459      * We have to keep the balance of lines from the first and the second document,
460      * so that corresponding lines will have the same line number in the document.
461      * Because some diff providers can be set not to report changes in empty lines,
462      * we have to use heuristics to balance the corresponding lines manually
463      * if they do not match.
464      * <p>
465      * This method goes through both documents and finds unreported differences
466      * in empty lines. Whenever it encounters an empty line with a corresponding
467      * non-empty line, which in not inside a difference (== unreported),
468      * it checks whether the following lines match (because there can be unreported
469      * difference in the amount of space rather than a missing or added line).
470      * If following lines "match", then silently add an empty line to the other
471      * document. This added line is not highlighted, since it was not reported
472      * as a difference.
473      */

474     private void insertEmptyLinesNotReported() {
475         String JavaDoc docText1 = diffPanel.getDocumentText1();
476         String JavaDoc docText2 = diffPanel.getDocumentText2();
477         int[] begin1 = { 0 };
478         int[] end1 = { -1 };
479         int[] begin2 = { 0 };
480         int[] end2 = { -1 };
481         int n1 = docText1.length();
482         int n2 = docText2.length();
483         int lineNumber = 1;
484         int diffIndex = 0;
485         do {
486             int lastBegin1 = begin1[0];
487             int lastBegin2 = begin2[0];
488             String JavaDoc line1 = readLine(begin1, end1, docText1);
489             String JavaDoc line2 = readLine(begin2, end2, docText2);
490             if (line1.length() == 0 && line2.length() > 0) {
491                 //System.out.println("Detected empty line LEFT "+lineNumber);
492
diffIndex = findDiffForLine(lineNumber, diffIndex, diffs, diffShifts);
493                 if (diffIndex >= diffs.length || !isLineInDiff(lineNumber, diffs[diffIndex], diffShifts[diffIndex])) {
494                     boolean addMissingLine;
495                     if (line2.trim().length() == 0) {
496                         int emptyLines1 = numEmptyLines(begin1[0], docText1, (diffIndex < diffs.length) ? diffs[diffIndex].getFirstStart() : -1);
497                         int emptyLines2 = numEmptyLines(begin2[0], docText2, (diffIndex < diffs.length) ? diffs[diffIndex].getSecondStart() : -1);
498                         addMissingLine = emptyLines1 > emptyLines2;
499                         //System.out.println("emptyLines1 = "+emptyLines1+", emptyLines2 = "+emptyLines2);
500
} else {
501                         addMissingLine = true;
502                     }
503                     if (addMissingLine) {
504                         addEmptyLines2(lineNumber - 1, 1);
505                         //highlightRegion2(lineNumber, lineNumber, colorAdded);
506
shiftDiffs(false, lineNumber);
507                         begin2[0] = lastBegin2;
508                         end2[0] = lastBegin2 - 1;
509                     }
510                 }
511             } else if (line2.length() == 0 && line1.length() > 0) {
512                 //System.out.println("Detected empty line RIGHT "+lineNumber);
513
diffIndex = findDiffForLine(lineNumber, diffIndex, diffs, diffShifts);
514                 if (diffIndex >= diffs.length || !isLineInDiff(lineNumber, diffs[diffIndex], diffShifts[diffIndex])) {
515                     boolean addMissingLine;
516                     if (line1.trim().length() == 0) {
517                         int emptyLines1 = numEmptyLines(begin1[0], docText1, (diffIndex < diffs.length) ? diffs[diffIndex].getFirstStart() : -1);
518                         int emptyLines2 = numEmptyLines(begin2[0], docText2, (diffIndex < diffs.length) ? diffs[diffIndex].getSecondStart() : -1);
519                         addMissingLine = emptyLines2 > emptyLines1;
520                         //System.out.println("emptyLines1 = "+emptyLines1+", emptyLines2 = "+emptyLines2);
521
} else {
522                         addMissingLine = true;
523                     }
524                     if (addMissingLine) {
525                         addEmptyLines1(lineNumber - 1, 1);
526                         //highlightRegion1(lineNumber, lineNumber, colorMissing);
527
shiftDiffs(true, lineNumber);
528                         begin1[0] = lastBegin1;
529                         end1[0] = lastBegin1 - 1;
530                     }
531                 }
532             }
533             lineNumber++;
534         } while (begin1[0] < n1 && begin2[0] < n2);
535     }
536     
537     /**
538      * Shift the differences by one in the first or the second document from the given line.
539      * @param inFirstDoc True to shift differences the first document, false for the second.
540      * @param fromLine The starting line. Shift all differences after this line.
541      */

542     private void shiftDiffs(boolean inFirstDoc, int fromLine) {
543         int n = diffs.length;
544         for(int i = 0; i < n; i++) {
545             Difference action = diffs[i];
546             if (inFirstDoc) {
547                 if (action.getFirstStart() + diffShifts[i][0] >= fromLine) {
548                     diffShifts[i][0]++;
549                 }
550             } else {
551                 if (action.getSecondStart() + diffShifts[i][1] >= fromLine) {
552                     diffShifts[i][1]++;
553                 }
554             }
555         }
556     }
557
558     public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException JavaDoc {
559         super.readExternal(in);
560         Object JavaDoc obj = in.readObject();
561         diffs = (Difference[]) obj;
562         diffPanel = new DiffPanel();
563         //this.diffSetSuccess = diff.setDiffComponent(this);
564
}
565     
566     private Object JavaDoc readResolve() throws ObjectStreamException {
567         if (this.diffSetSuccess) return this;
568         else return null;
569     }
570     
571     /**
572      * Disable serialization.
573      */

574     protected Object JavaDoc writeReplace () throws java.io.ObjectStreamException JavaDoc {
575         exitForm(null);
576         return null;
577     }
578     
579        /** Exit the Application */
580     private void exitForm(java.awt.event.WindowEvent JavaDoc evt) {
581         SwingUtilities.invokeLater(new Runnable JavaDoc() {
582             public void run() {
583                 diffPanel = null;
584                 diffs = null;
585                 removeAll();
586             }
587         });
588         /*
589         try {
590             org.netbeans.editor.Settings.setValue(null, org.netbeans.editor.SettingsNames.LINE_NUMBER_VISIBLE, lineNumbersVisible);
591         } catch (Throwable exc) {
592             // editor module not found
593         }
594          */

595         //System.out.println("exitForm() called.");
596
//diff.closing();
597
//close();
598
//dispose ();
599
/*
600         for(Iterator it = closeListeners.iterator(); it.hasNext(); ) {
601             ((TopComponentCloseListener) it.next()).closing();
602         }
603          */

604  
605     }
606
607 }
608
Popular Tags