KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > merge > builtin > visualizer > MergeControl


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.merge.builtin.visualizer;
21
22 import java.awt.Color JavaDoc;
23 import java.awt.event.ActionEvent JavaDoc;
24 import java.awt.event.ActionListener JavaDoc;
25 import java.beans.PropertyChangeEvent JavaDoc;
26 import java.beans.PropertyVetoException JavaDoc;
27 import java.beans.VetoableChangeListener JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.util.ArrayList JavaDoc;
30 import java.util.Set JavaDoc;
31 import java.util.HashSet JavaDoc;
32
33 import org.openide.util.NbBundle;
34
35 import org.netbeans.api.diff.Difference;
36 import org.netbeans.api.diff.StreamSource;
37
38 /**
39  * This class controls the merge process.
40  *
41  * @author Martin Entlicher
42  */

43 public class MergeControl extends Object JavaDoc implements ActionListener JavaDoc, VetoableChangeListener JavaDoc {
44     
45     private Color JavaDoc colorUnresolvedConflict;
46     private Color JavaDoc colorResolvedConflict;
47     private Color JavaDoc colorOtherConflict;
48     
49     private MergePanel panel;
50     private Difference[] diffs;
51     /** The shift of differences */
52     private int[][] diffShifts;
53     /** The current diff */
54     private int currentDiffLine = 0;
55     private int[] resultDiffLocations;
56     private Set JavaDoc<Difference> resolvedConflicts = new HashSet JavaDoc<Difference>();
57     private StreamSource resultSource;
58     
59     private boolean firstNewlineIsFake;
60     private boolean secondNewlineIsFake;
61
62     /** Creates a new instance of MergeControl */
63     public MergeControl(MergePanel panel) {
64         this.panel = panel;
65     }
66     
67     public void initialize(Difference[] diffs, StreamSource source1,
68                            StreamSource source2, StreamSource result,
69                            Color JavaDoc colorUnresolvedConflict, Color JavaDoc colorResolvedConflict,
70                            Color JavaDoc colorOtherConflict) {
71         if (diffs.length > 0) {
72             // all lines must end with a newline
73
Difference ld = diffs[diffs.length - 1];
74             if (!ld.getFirstText().endsWith("\n")) {
75                 firstNewlineIsFake = true;
76             }
77             if (!ld.getSecondText().endsWith("\n")) {
78                 secondNewlineIsFake = true;
79             }
80             if (firstNewlineIsFake || secondNewlineIsFake) {
81                 diffs[diffs.length - 1] = new Difference(
82                         ld.getType(), ld.getFirstStart(), ld.getFirstEnd(), ld.getSecondStart(), ld.getSecondEnd(),
83                         ld.getFirstText() + (firstNewlineIsFake ? "\n" : ""),
84                         ld.getSecondText() + (secondNewlineIsFake ? "\n" : ""));
85             }
86         }
87         this.diffs = diffs;
88         this.diffShifts = new int[diffs.length][2];
89         this.resultDiffLocations = new int[diffs.length];
90         panel.setMimeType1(source1.getMIMEType());
91         panel.setMimeType2(source2.getMIMEType());
92         panel.setMimeType3(result.getMIMEType());
93         panel.setSource1Title(source1.getTitle());
94         panel.setSource2Title(source2.getTitle());
95         panel.setResultSourceTitle(result.getTitle());
96         panel.setName(source1.getName());
97         try {
98             panel.setSource1(source1.createReader());
99             panel.setSource2(source2.createReader());
100             panel.setResultSource(new java.io.StringReader JavaDoc(""));
101         } catch (IOException JavaDoc ioex) {
102             org.openide.ErrorManager.getDefault().notify(ioex);
103         }
104         this.colorUnresolvedConflict = colorUnresolvedConflict;
105         this.colorResolvedConflict = colorResolvedConflict;
106         this.colorOtherConflict = colorOtherConflict;
107         insertEmptyLines(true);
108         setDiffHighlight(true);
109         copyToResult();
110         panel.setNumConflicts(diffs.length);
111         panel.addControlActionListener(this);
112         showCurrentLine();
113         this.resultSource = result;
114     }
115     
116     private void insertEmptyLines(boolean updateActionLines) {
117         int n = diffs.length;
118         for(int i = 0; i < n; i++) {
119             Difference action = diffs[i];
120             int n1 = action.getFirstStart() + diffShifts[i][0];
121             int n2 = action.getFirstEnd() + diffShifts[i][0];
122             int n3 = action.getSecondStart() + diffShifts[i][1];
123             int n4 = action.getSecondEnd() + diffShifts[i][1];
124             if (updateActionLines && i < n - 1) {
125                 diffShifts[i + 1][0] = diffShifts[i][0];
126                 diffShifts[i + 1][1] = diffShifts[i][1];
127             }
128             switch (action.getType()) {
129                 case Difference.DELETE:
130                     panel.addEmptyLines2(n3, n2 - n1 + 1);
131                     if (updateActionLines && i < n - 1) {
132                         diffShifts[i+1][1] += n2 - n1 + 1;
133                     }
134                     break;
135                 case Difference.ADD:
136                     panel.addEmptyLines1(n1, n4 - n3 + 1);
137                     if (updateActionLines && i < n - 1) {
138                         diffShifts[i+1][0] += n4 - n3 + 1;
139                     }
140                     break;
141                 case Difference.CHANGE:
142                     int r1 = n2 - n1;
143                     int r2 = n4 - n3;
144                     if (r1 < r2) {
145                         panel.addEmptyLines1(n2, r2 - r1);
146                         if (updateActionLines && i < n - 1) {
147                             diffShifts[i+1][0] += r2 - r1;
148                         }
149                     } else if (r1 > r2) {
150                         panel.addEmptyLines2(n4, r1 - r2);
151                         if (updateActionLines && i < n - 1) {
152                             diffShifts[i+1][1] += r1 - r2;
153                         }
154                     }
155                     break;
156             }
157         }
158     }
159     
160     private void setDiffHighlight(boolean set) {
161         int n = diffs.length;
162         //D.deb("Num Actions = "+n); // NOI18N
163
for(int i = 0; i < n; i++) {
164             Difference action = diffs[i];
165             int n1 = action.getFirstStart() + diffShifts[i][0];
166             int n2 = action.getFirstEnd() + diffShifts[i][0];
167             int n3 = action.getSecondStart() + diffShifts[i][1];
168             int n4 = action.getSecondEnd() + diffShifts[i][1];
169             //D.deb("Action: "+action.getAction()+": ("+n1+","+n2+","+n3+","+n4+")"); // NOI18N
170
switch (action.getType()) {
171             case Difference.DELETE:
172                 if (set) panel.highlightRegion1(n1, n2, colorUnresolvedConflict);
173                 else panel.highlightRegion1(n1, n2, java.awt.Color.white);
174                 break;
175             case Difference.ADD:
176                 if (set) panel.highlightRegion2(n3, n4, colorUnresolvedConflict);
177                 else panel.highlightRegion2(n3, n4, java.awt.Color.white);
178                 break;
179             case Difference.CHANGE:
180                 if (set) {
181                     panel.highlightRegion1(n1, n2, colorUnresolvedConflict);
182                     panel.highlightRegion2(n3, n4, colorUnresolvedConflict);
183                 } else {
184                     panel.highlightRegion1(n1, n2, java.awt.Color.white);
185                     panel.highlightRegion2(n3, n4, java.awt.Color.white);
186                 }
187                 break;
188             }
189         }
190     }
191     
192     private void copyToResult() {
193         int n = diffs.length;
194         int line1 = 1;
195         int line3 = 1;
196         for(int i = 0; i < n; i++) {
197             Difference action = diffs[i];
198             int n1 = action.getFirstStart() + diffShifts[i][0];
199             int n2 = action.getFirstEnd() + diffShifts[i][0];
200             int n3 = action.getSecondStart() + diffShifts[i][1];
201             int n4 = action.getSecondEnd() + diffShifts[i][1];
202             int endcopy = (action.getType() != Difference.ADD) ? (n1 - 1) : n1;
203             //System.out.println("diff = "+n1+", "+n2+", "+n3+", "+n4+", endcopy = "+endcopy+((endcopy >= line1) ? "; copy("+line1+", "+endcopy+", "+line3+")" : ""));
204
if (endcopy >= line1) {
205                 panel.copySource1ToResult(line1, endcopy, line3);
206                 line3 += endcopy + 1 - line1;
207             }
208             int length = Math.max(n2 - n1, n4 - n3);
209             //System.out.println(" length = "+length+", addEmptyLines3("+line3+", "+(length + 1)+")");
210
panel.addEmptyLines3(line3, length + 1);
211             panel.highlightRegion3(line3, line3 + length, colorUnresolvedConflict);
212             resultDiffLocations[i] = line3;
213             line3 += length + 1;
214             line1 = Math.max(n2, n4) + 1;
215         }
216         //System.out.println("copy("+line1+", -1, "+line3+")");
217
panel.copySource1ToResult(line1, -1, line3);
218     }
219
220     private void showCurrentLine() {
221         Difference diff = diffs[currentDiffLine];
222         int line = diff.getFirstStart() + diffShifts[currentDiffLine][0];
223         if (diff.getType() == Difference.ADD) line++;
224         int lf1 = diff.getFirstEnd() - diff.getFirstStart() + 1;
225         int lf2 = diff.getSecondEnd() - diff.getSecondStart() + 1;
226         int length = Math.max(lf1, lf2);
227         panel.setCurrentLine(line, length, currentDiffLine,
228                              resultDiffLocations[currentDiffLine]);
229     }
230     
231     /**
232      * Resolve the merge conflict with left or right part.
233      * This will reduce the number of conflicts by one.
234      * @param right If true, use the right part, left otherwise
235      * @param conflNum The number of conflict.
236      */

237     private void doResolveConflict(boolean right, int conflNum) {
238         Difference diff = diffs[conflNum];
239         int[] shifts = diffShifts[conflNum];
240         int line1, line2, line3, line4;
241         if (diff.getType() == Difference.ADD) {
242             line1 = diff.getFirstStart() + shifts[0] + 1;
243             line2 = line1 - 1;
244         } else {
245             line1 = diff.getFirstStart() + shifts[0];
246             line2 = diff.getFirstEnd() + shifts[0];
247         }
248         if (diff.getType() == Difference.DELETE) {
249             line3 = diff.getSecondStart() + shifts[1] + 1;
250             line4 = line3 - 1;
251         } else {
252             line3 = diff.getSecondStart() + shifts[1];
253             line4 = diff.getSecondEnd() + shifts[1];
254         }
255         //System.out.println(" diff lines = "+line1+", "+line2+", "+line3+", "+line4);
256
int rlength; // The length of the area before the conflict is resolved
257
if (resolvedConflicts.contains(diff)) {
258             rlength = (right) ? (line2 - line1) : (line4 - line3);
259         } else {
260             rlength = Math.max(line2 - line1, line4 - line3);
261         }
262         int shift;
263         if (right) {
264             panel.replaceSource2InResult(line3, Math.max(line4, 0), // Correction for possibly negative value
265
resultDiffLocations[conflNum],
266                                          resultDiffLocations[conflNum] + rlength);
267             shift = rlength - (line4 - line3);
268             panel.highlightRegion1(line1, Math.max(line2, 0), colorOtherConflict);
269             panel.highlightRegion2(line3, Math.max(line4, 0), colorResolvedConflict);
270         } else {
271             panel.replaceSource1InResult(line1, Math.max(line2, 0), // Correction for possibly negative value
272
resultDiffLocations[conflNum],
273                                          resultDiffLocations[conflNum] + rlength);
274             shift = rlength - (line2 - line1);
275             panel.highlightRegion1(line1, Math.max(line2, 0), colorResolvedConflict);
276             panel.highlightRegion2(line3, Math.max(line4, 0), colorOtherConflict);
277         }
278         if (right && (line4 >= line3) || !right && (line2 >= line1)) {
279             panel.highlightRegion3(resultDiffLocations[conflNum],
280                                    resultDiffLocations[conflNum] + rlength - shift,
281                                    colorResolvedConflict);
282         } else {
283             panel.unhighlightRegion3(resultDiffLocations[conflNum],
284                                      resultDiffLocations[conflNum]);
285         }
286         for (int i = conflNum + 1; i < diffs.length; i++) {
287             resultDiffLocations[i] -= shift;
288         }
289         resolvedConflicts.add(diff);
290         panel.setNeedsSaveState(true);
291     }
292     
293     public void actionPerformed(ActionEvent JavaDoc actionEvent) {
294         String JavaDoc actionCommand = actionEvent.getActionCommand();
295         if (MergePanel.ACTION_FIRST_CONFLICT.equals(actionCommand)) {
296             currentDiffLine = 0;
297             showCurrentLine();
298         } else if (MergePanel.ACTION_LAST_CONFLICT.equals(actionCommand)) {
299             currentDiffLine = diffs.length - 1;
300             showCurrentLine();
301         } else if (MergePanel.ACTION_PREVIOUS_CONFLICT.equals(actionCommand)) {
302             currentDiffLine--;
303             if (currentDiffLine < 0) currentDiffLine = diffs.length - 1;
304             showCurrentLine();
305         } else if (MergePanel.ACTION_NEXT_CONFLICT.equals(actionCommand)) {
306             currentDiffLine++;
307             if (currentDiffLine >= diffs.length) currentDiffLine = 0;
308             showCurrentLine();
309         } else if (MergePanel.ACTION_ACCEPT_RIGHT.equals(actionCommand)) {
310             doResolveConflict(true, currentDiffLine);
311         } else if (MergePanel.ACTION_ACCEPT_LEFT.equals(actionCommand)) {
312             doResolveConflict(false, currentDiffLine);
313         }
314     }
315     
316     public void vetoableChange(PropertyChangeEvent JavaDoc propertyChangeEvent) throws PropertyVetoException JavaDoc {
317         if (MergeDialogComponent.PROP_PANEL_SAVE.equals(propertyChangeEvent.getPropertyName())) {
318             MergePanel panel = (MergePanel) propertyChangeEvent.getNewValue();
319             if (this.panel == panel) {
320                 ArrayList JavaDoc<Difference> unresolvedConflicts = new ArrayList JavaDoc<Difference>();//java.util.Arrays.asList(diffs));
321
int diffLocationShift = 0;
322                 for (int i = 0; i < diffs.length; i++) {
323                     if (!resolvedConflicts.contains(diffs[i])) {
324                         int diffLocation = resultDiffLocations[i] - diffLocationShift;
325                         Difference conflict = new Difference(diffs[i].getType(),
326                                                              diffLocation,
327                                                              diffLocation + diffs[i].getFirstEnd() - diffs[i].getFirstStart(),
328                                                              diffLocation,
329                                                              diffLocation + diffs[i].getSecondEnd() - diffs[i].getSecondStart(),
330                                                              diffs[i].getFirstText(),
331                                                              diffs[i].getSecondText());
332                         unresolvedConflicts.add(conflict);
333                         diffLocationShift += Math.max(diffs[i].getFirstEnd() - diffs[i].getFirstStart() + 1,
334                                                       diffs[i].getSecondEnd() - diffs[i].getSecondStart() + 1);
335                     }
336                 }
337                 try {
338                     panel.writeResult(resultSource.createWriter(unresolvedConflicts.toArray(
339                         new Difference[unresolvedConflicts.size()])), firstNewlineIsFake | secondNewlineIsFake);
340                     panel.setNeedsSaveState(false);
341                 } catch (IOException JavaDoc ioex) {
342                     PropertyVetoException JavaDoc pvex =
343                         new PropertyVetoException JavaDoc(NbBundle.getMessage(MergeControl.class,
344                                                                       "MergeControl.failedToSave",
345                                                                       ioex.getLocalizedMessage()),
346                                                   propertyChangeEvent);
347                     pvex.initCause(ioex);
348                     throw pvex;
349                 }
350             }
351         }
352         if (MergeDialogComponent.PROP_PANEL_CLOSING.equals(propertyChangeEvent.getPropertyName())) {
353             MergePanel panel = (MergePanel) propertyChangeEvent.getNewValue();
354             if (this.panel == panel) {
355                 resultSource.close();
356             }
357         }
358         if (MergeDialogComponent.PROP_ALL_CLOSED.equals(propertyChangeEvent.getPropertyName()) ||
359             MergeDialogComponent.PROP_ALL_CANCELLED.equals(propertyChangeEvent.getPropertyName())) {
360                 resultSource.close();
361         }
362     }
363     
364 }
365
Popular Tags