1 19 20 package org.netbeans.modules.merge.builtin.visualizer; 21 22 import java.awt.Color ; 23 import java.awt.event.ActionEvent ; 24 import java.awt.event.ActionListener ; 25 import java.beans.PropertyChangeEvent ; 26 import java.beans.PropertyVetoException ; 27 import java.beans.VetoableChangeListener ; 28 import java.io.IOException ; 29 import java.util.ArrayList ; 30 import java.util.Set ; 31 import java.util.HashSet ; 32 33 import org.openide.util.NbBundle; 34 35 import org.netbeans.api.diff.Difference; 36 import org.netbeans.api.diff.StreamSource; 37 38 43 public class MergeControl extends Object implements ActionListener , VetoableChangeListener { 44 45 private Color colorUnresolvedConflict; 46 private Color colorResolvedConflict; 47 private Color colorOtherConflict; 48 49 private MergePanel panel; 50 private Difference[] diffs; 51 52 private int[][] diffShifts; 53 54 private int currentDiffLine = 0; 55 private int[] resultDiffLocations; 56 private Set <Difference> resolvedConflicts = new HashSet <Difference>(); 57 private StreamSource resultSource; 58 59 private boolean firstNewlineIsFake; 60 private boolean secondNewlineIsFake; 61 62 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 colorUnresolvedConflict, Color colorResolvedConflict, 70 Color colorOtherConflict) { 71 if (diffs.length > 0) { 72 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 ("")); 101 } catch (IOException 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 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 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 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 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 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 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 int rlength; 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), 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), 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 actionEvent) { 294 String 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 propertyChangeEvent) throws PropertyVetoException { 317 if (MergeDialogComponent.PROP_PANEL_SAVE.equals(propertyChangeEvent.getPropertyName())) { 318 MergePanel panel = (MergePanel) propertyChangeEvent.getNewValue(); 319 if (this.panel == panel) { 320 ArrayList <Difference> unresolvedConflicts = new ArrayList <Difference>(); 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 ioex) { 342 PropertyVetoException pvex = 343 new PropertyVetoException (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 |