/* * DiffWindowController.m * * Copyright (c) 2002 Pierre-Yves Rivaille * * This file is part of EasyDiff.app. * * EasyDiff.app is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * EasyDiff.app is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with EasyDiff.app; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include //#include "DiffTextView.h" //#include "DiffMiddleView.h" #include "DiffView.h" #include "DiffWindowController.h" #include "DiffWrapper.h" //extern void tasktest(NSString *file1, NSString *file2, NSMutableArray **r1, NSMutableArray **r2); @interface PatchData : NSObject { @public NSMutableString *patchString; int start; int end; int lineDifference; } @end @implementation PatchData @end @interface DiffWindowController (Private) - (void) diffViewFrameDidChange: (NSNotification*) aNotification; - (id) _initWithFilename: (NSString *) filename1 andFilename: (NSString *) filename2; - (NSMutableString *) _patchMutableString: (int) direction; - (void) saveMergedAt: (NSString *) mergedName; @end @implementation DiffWindowController - (id) initWithFilename: (NSString *) filename1 andTempFilename: (NSString *) filename2 { [self _initWithFilename: filename1 andFilename: filename2]; tempFilename = filename2; [[self window] setTitle: [NSString stringWithFormat: @"Comparing %@ to the CVS version", [filename1 lastPathComponent]]]; [[self window] makeKeyAndOrderFront: self]; leftFileName = RETAIN(filename1); rightFileName = nil; return self; } - (id) initWithFilename: (NSString *) filename1 andFilename: (NSString *) filename2 { [self _initWithFilename: filename1 andFilename: filename2]; tempFilename = nil; [[self window] setTitle: [NSString stringWithFormat: @"Comparing %@ to %@", [filename1 lastPathComponent], [filename2 lastPathComponent]]]; [[self window] makeKeyAndOrderFront: self]; /* [NSApp addWindowsItem: [self window] title: [[self window] title] filename: NO]; */ leftFileName = RETAIN(filename1); rightFileName = RETAIN(filename2); NSDebugLog(@"windowsMenu %@", [NSApp windowsMenu]); return self; } - (id) _initWithFilename: (NSString *) filename1 andFilename: (NSString *) filename2 { [self initWithWindowNibName: @"window"]; [self window]; NSDebugLog(@"%@", scroller); [scroller setArrowsPosition: NSScrollerArrowsMaxEnd]; [scroller setFloatValue:0.5 knobProportion:0.2]; [scroller setEnabled: YES]; diffWrapper = [[DiffWrapper alloc] initWithFilename: filename1 andFilename: filename2]; [diffWrapper compare]; leftChanges = [diffWrapper leftChanges]; rightChanges = [diffWrapper rightChanges]; // tasktest(filename1, filename2, &leftChanges, &rightChanges); RETAIN(leftChanges); RETAIN(rightChanges); { NSString *string1; NSString *string2; string1 = [NSString stringWithContentsOfFile: filename1]; string2 = [NSString stringWithContentsOfFile: filename2]; [diffView setLeftString: string1]; [diffView setRightString: string2]; [diffView setLeftChanges: leftChanges andRightChanges: rightChanges]; [diffView setLeftLineRanges: [diffWrapper leftLineRanges] andRightLineRanges: [diffWrapper rightLineRanges]]; [scroller setFloatValue: 0. knobProportion: ([diffView frame].size.height / [diffView mergeFileHeight])]; [diffView tile]; [diffView setPostsFrameChangedNotifications: YES]; [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(diffViewFrameDidChange:) name: NSViewFrameDidChangeNotification object: diffView]; choices = (int *) calloc([leftChanges count], sizeof(int)); } // NSLog(@"gonna orderFront %@",[self window]); [self diffViewFrameDidChange: nil]; // [[self window] orderFrontRegardless]; return self; } - (void) diffViewFrameDidChange: (NSNotification*) aNotification { [diffView computeScrollerSize]; if ([diffView frame].size.height >= [diffView mergeFileHeight]) { [scroller setEnabled: NO]; } else { [scroller setEnabled: YES]; [scroller setFloatValue: [scroller floatValue] knobProportion: ([diffView frame].size.height / [diffView mergeFileHeight])]; [diffView doScroll: scroller]; } } - (void) windowWillClose: (id) sender { NSDebugLog(@"windowWillClose called"); // RELEASE([self window]); AUTORELEASE(self); } - (void) dealloc { NSDebugLog(@"dealloc called"); if (tempFilename != nil) { if ([[NSFileManager defaultManager] removeFileAtPath: tempFilename handler: nil] == NO) NSLog(@"We could not delete %@", tempFilename); } TEST_RELEASE(leftFileName); TEST_RELEASE(rightFileName); [super dealloc]; } - (void) matrixButtonClicked: (id) sender { int oldChoice = choices[[sender tag]]; NSDebugLog(@"matrixButtonClicked %d, %d", [sender tag], [sender selectedColumn]); choices[[sender tag]] = [sender selectedColumn] - 1; if ((oldChoice == -1) && (choices[[sender tag]] != -1)) { [[diffView leftTextView] setColor: [NSColor colorWithDeviceRed:0.7 green:0.7 blue:1. alpha:1.] forChangeNumber: [sender tag]]; } else if ((oldChoice != -1) && (choices[[sender tag]] == -1)) { [[diffView leftTextView] setColor: [NSColor whiteColor] forChangeNumber: [sender tag]]; } if ((oldChoice == 1) && (choices[[sender tag]] != 1)) { [[diffView rightTextView] setColor: [NSColor colorWithDeviceRed:0.7 green:0.7 blue:1. alpha:1.] forChangeNumber: [sender tag]]; } else if ((oldChoice != 1) && (choices[[sender tag]] == 1)) { [[diffView rightTextView] setColor: [NSColor whiteColor] forChangeNumber: [sender tag]]; } } - (void) selectAllLeftChanges: (id) sender { int i; NSArray *matrixArray = [[diffView middleView] matrixArray]; int count = [matrixArray count]; for ( i = 0; i < count; i ++ ) { if (choices[i] != - 1) { choices[i] = -1; [[diffView leftTextView] setColor: [NSColor whiteColor] forChangeNumber: i]; [[diffView rightTextView] setColor: [NSColor colorWithDeviceRed:0.7 green:0.7 blue:1. alpha:1.] forChangeNumber: i]; [[matrixArray objectAtIndex: i] selectCellAtRow: 0 column:0]; } } } - (void) selectAllRightChanges: (id) sender { int i; NSArray *matrixArray = [[diffView middleView] matrixArray]; int count = [matrixArray count]; for ( i = 0; i < count; i ++ ) { if (choices[i] != 1) { choices[i] = 1; [[diffView rightTextView] setColor: [NSColor whiteColor] forChangeNumber: i]; [[diffView leftTextView] setColor: [NSColor colorWithDeviceRed:0.7 green:0.7 blue:1. alpha:1.] forChangeNumber: i]; [[matrixArray objectAtIndex: i] selectCellAtRow: 0 column:2]; } } } - (void) selectNoChanges: (id) sender { int i; NSArray *matrixArray = [[diffView middleView] matrixArray]; int count = [matrixArray count]; for ( i = 0; i < count; i ++ ) { if (choices[i] != 0) { choices[i] = 0; [[diffView leftTextView] setColor: [NSColor colorWithDeviceRed:0.7 green:0.7 blue:1. alpha:1.] forChangeNumber: i]; [[diffView rightTextView] setColor: [NSColor colorWithDeviceRed:0.7 green:0.7 blue:1. alpha:1.] forChangeNumber: i]; [[matrixArray objectAtIndex: i] selectCellAtRow: 0 column:1]; } } } - (void) savePatchFromRight: (id) sender { NSMutableString *patchString; int result; NSSavePanel *sPanel; NSString *path = [[NSUserDefaults standardUserDefaults] objectForKey:@"OpenDirectory"]; NSString *mergedName; sPanel = [NSSavePanel savePanel]; // [sPanel setAllowsMultipleSelection:NO]; result = [sPanel runModalForDirectory: path file: @""]; if (result != NSOKButton) return; path = [sPanel directory]; mergedName = [sPanel filename]; [[NSUserDefaults standardUserDefaults] setObject: path forKey:@"OpenDirectory"]; patchString = [self _patchMutableString: -1]; [patchString insertString: [NSString stringWithFormat: @"+++ %@\n", leftFileName] atIndex: 0]; if (rightFileName) { [patchString insertString: [NSString stringWithFormat: @"--- %@\n", rightFileName] atIndex: 0]; } else { [patchString insertString: [NSString stringWithFormat: @"--- %@\n", leftFileName] atIndex: 0]; } [patchString writeToFile: mergedName atomically: YES]; } - (void) savePatchFromLeft: (id) sender { NSMutableString *patchString; int result; NSSavePanel *sPanel; NSString *path = [[NSUserDefaults standardUserDefaults] objectForKey:@"OpenDirectory"]; NSString *mergedName; sPanel = [NSSavePanel savePanel]; // [sPanel setAllowsMultipleSelection:NO]; result = [sPanel runModalForDirectory: path file: @""]; if (result != NSOKButton) return; path = [sPanel directory]; mergedName = [sPanel filename]; [[NSUserDefaults standardUserDefaults] setObject: path forKey:@"OpenDirectory"]; patchString = [self _patchMutableString: 1]; if (rightFileName) { [patchString insertString: [NSString stringWithFormat: @"+++ %@\n", rightFileName] atIndex: 0]; } else { [patchString insertString: [NSString stringWithFormat: @"+++ %@\n", leftFileName] atIndex: 0]; } [patchString insertString: [NSString stringWithFormat: @"--- %@\n", leftFileName] atIndex: 0]; [patchString writeToFile: mergedName atomically: YES]; } - (NSMutableString *) _patchMutableString: (int) direction { NSArray *flr; NSArray *tlr; NSString *fstr; NSString *tstr; NSMutableArray *patchArray = [[NSMutableArray alloc] initWithCapacity: ([leftChanges count] / 2) + 1]; NSMutableArray *finalArray = [[NSMutableArray alloc] initWithCapacity: ([leftChanges count] / 2) + 1]; NSArray *fromChanges; NSArray *toChanges; NSMutableString *stringToInsert; PatchData *p, *pp; int i, j, k; int toStart; int toEnd; int count; int linesCount; if (direction > 0) { flr = [diffWrapper leftLineRanges]; tlr = [diffWrapper rightLineRanges]; fstr = [diffWrapper leftString]; tstr = [diffWrapper rightString]; fromChanges = leftChanges; toChanges = rightChanges; } else { flr = [diffWrapper rightLineRanges]; tlr = [diffWrapper leftLineRanges]; fstr = [diffWrapper rightString]; tstr = [diffWrapper leftString]; fromChanges = rightChanges; toChanges = leftChanges; } linesCount = [flr count] - 1; for ( i = 0; i < [fromChanges count] - 1; i += 2 ) { p = [[PatchData alloc] init]; p->patchString = (NSMutableString*)[NSMutableString string]; if (choices[i/2] * direction > 0) { p->start = [[fromChanges objectAtIndex: i] intValue]; p->end = [[fromChanges objectAtIndex: i + 1] intValue]; toStart = [[toChanges objectAtIndex: i] intValue]; toEnd = [[toChanges objectAtIndex: i + 1] intValue]; p->lineDifference = (toEnd - toStart) - (p->end - p->start); for (j = p->start; j < p->end; j++ ) { [p->patchString appendString: @"-"]; [p->patchString appendString:[fstr substringWithRange: NSMakeRange ([[flr objectAtIndex: j] intValue] + 1, [[flr objectAtIndex: j+1] intValue] - [[flr objectAtIndex: j] intValue])]]; } for (j = toStart; j < toEnd; j++ ) { [p->patchString appendString: @"+"]; [p->patchString appendString:[tstr substringWithRange: NSMakeRange ([[tlr objectAtIndex: j] intValue] + 1, [[tlr objectAtIndex: j+1] intValue] - [[tlr objectAtIndex: j] intValue])]]; } [patchArray addObject: p]; } else if (choices[i/2] * direction < 0) { } else if (choices[i/2] == 0) { p->start = [[fromChanges objectAtIndex: i] intValue]; p->end = [[fromChanges objectAtIndex: i + 1] intValue]; p->lineDifference = - (p->end - p->start); for (j = p->start; j < p->end; j++ ) { [p->patchString appendString: @"-"]; [p->patchString appendString:[fstr substringWithRange: NSMakeRange ([[flr objectAtIndex: j] intValue] + 1, [[flr objectAtIndex: j+1] intValue] - [[flr objectAtIndex: j] intValue])]]; } if (p->lineDifference != 0) [patchArray addObject: p]; } } i = 0; count = [patchArray count]; pp = nil; while( i < count ) { p = [patchArray objectAtIndex: i]; if ((pp == nil) || (p->start - pp->end >= 6)) { // two separate chunks if (pp != nil) { j = pp->end + 3; if (j >= linesCount) j = linesCount; stringToInsert = (NSMutableString*)[NSMutableString string]; for ( k = pp->end; k < j; k++ ) { [stringToInsert appendString: @" "]; [stringToInsert appendString: [fstr substringWithRange: NSMakeRange ([[flr objectAtIndex: k] intValue] + 1, [[flr objectAtIndex: k+1] intValue] - [[flr objectAtIndex: k] intValue])]]; } [pp->patchString appendString: stringToInsert]; pp->end = j; [finalArray addObject: pp]; } // new chunk pp = [[PatchData alloc] init];; j = p->start - 3; if ( j < 0) j = 0; pp = [[PatchData alloc] init]; pp->patchString = p->patchString; stringToInsert = (NSMutableString*)[NSMutableString string]; for ( k = j; k < p->start; k++ ) { [stringToInsert appendString: @" "]; [stringToInsert appendString: [fstr substringWithRange: NSMakeRange ([[flr objectAtIndex: k] intValue] + 1, [[flr objectAtIndex: k+1] intValue] - [[flr objectAtIndex: k] intValue])]]; } [pp->patchString insertString: stringToInsert atIndex: 0]; pp->start = j; pp->end = p->end; pp->lineDifference = p->lineDifference; } else { // merge the two chunks stringToInsert = (NSMutableString*)[NSMutableString string]; for ( k = pp->end; k < p->start; k++ ) { [stringToInsert appendString: @" "]; [stringToInsert appendString: [fstr substringWithRange: NSMakeRange ([[flr objectAtIndex: k] intValue] + 1, [[flr objectAtIndex: k+1] intValue] - [[flr objectAtIndex: k] intValue])]]; } [pp->patchString appendString: stringToInsert]; [pp->patchString appendString: p->patchString]; pp->end = p->end; pp->lineDifference += p->lineDifference; } i++; } if (pp != nil) { j = pp->end + 3; if (j >= linesCount) j = linesCount; stringToInsert = (NSMutableString*)[NSMutableString string]; for ( k = pp->end; k < j; k++ ) { [stringToInsert appendString: @" "]; [stringToInsert appendString: [fstr substringWithRange: NSMakeRange ([[flr objectAtIndex: k] intValue] + 1, [[flr objectAtIndex: k+1] intValue] - [[flr objectAtIndex: k] intValue])]]; } [pp->patchString appendString: stringToInsert]; pp->end = j; [finalArray addObject: pp]; } { NSMutableString *patchFileString = (NSMutableString*)[NSMutableString string]; int d = 0; for ( i = 0; i < [finalArray count]; i++ ) { p = [finalArray objectAtIndex: i]; [patchFileString appendFormat: @"@@ -%d,%d +%d,%d @@\n%@", p->start+1, p->end - p->start, p->start + d + 1, p->end - p->start + p->lineDifference, p->patchString]; d += p->lineDifference; } // NSLog(@"\n%@", patchFileString); return patchFileString; } } - (void) saveMergedAt: (NSString *) mergedName { NSMutableString *mergedString = [NSMutableString string]; int i; { NSArray *llr = [diffWrapper leftLineRanges]; NSArray *rlr = [diffWrapper rightLineRanges]; [mergedString appendString: [[diffWrapper leftString] substringWithRange: NSMakeRange (0, [[llr objectAtIndex: [[leftChanges objectAtIndex: 0] intValue]] intValue] )]]; for ( i = 0; i < [leftChanges count] - 1; i++ ) { if (i % 2 == 1) { [mergedString appendString: [[diffWrapper leftString] substringWithRange: NSMakeRange ([[llr objectAtIndex: [[leftChanges objectAtIndex: i] intValue]] intValue], [[llr objectAtIndex: [[leftChanges objectAtIndex: i+1] intValue]] intValue] - [[llr objectAtIndex: [[leftChanges objectAtIndex: i] intValue]] intValue] )]]; } else { if (choices[i/2] < 0) { [mergedString appendString: [[diffWrapper leftString] substringWithRange: NSMakeRange ([[llr objectAtIndex: [[leftChanges objectAtIndex: i] intValue]] intValue], [[llr objectAtIndex: [[leftChanges objectAtIndex: i+1] intValue]] intValue] - [[llr objectAtIndex: [[leftChanges objectAtIndex: i] intValue]] intValue] )]]; } else if (choices[i/2] > 0) { [mergedString appendString: [[diffWrapper rightString] substringWithRange: NSMakeRange ([[rlr objectAtIndex: [[rightChanges objectAtIndex: i] intValue]] intValue], [[rlr objectAtIndex: [[rightChanges objectAtIndex: i+1] intValue]] intValue] - [[rlr objectAtIndex: [[rightChanges objectAtIndex: i] intValue]] intValue] )]]; } else { } } } [mergedString appendString: [[diffWrapper leftString] substringFromIndex: [[llr objectAtIndex: [[leftChanges objectAtIndex: [leftChanges count] - 1] intValue]] intValue]]]; // NSLog(@"%@", mergedString); } [mergedString writeToFile: mergedName atomically: YES]; } - (void) saveMergedFile: (id) sender { int result; NSSavePanel *sPanel; NSString *path = [[NSUserDefaults standardUserDefaults] objectForKey:@"OpenDirectory"]; NSString *mergedName; sPanel = [NSSavePanel savePanel]; // [sPanel setAllowsMultipleSelection:NO]; result = [sPanel runModalForDirectory: path file: @""]; if (result != NSOKButton) return; path = [sPanel directory]; mergedName = [sPanel filename]; [[NSUserDefaults standardUserDefaults] setObject: path forKey:@"OpenDirectory"]; // NSLog(@"%@", mergedName); [self saveMergedAt: mergedName]; } @end