From a29096ca5c886fef62cb27a91db78300799a2ca0 Mon Sep 17 00:00:00 2001 From: Antoine Mercadal Date: Sat, 5 Nov 2011 16:46:34 +0100 Subject: [PATCH] Some other improvments - Add preferences window - Allow user to choose to use the 10.6 mode on 10.7 - Allow user to choose if he wants to resume listening at startup - Allow use to choose if XCC should react to inode modification (file level API) - Support for clean mirrored path when origin files has some _ in their names - Other various fixes --- Tools/xcodecapp-cocoa/AppController.h | 37 +- Tools/xcodecapp-cocoa/AppController.m | 27 +- .../English.lproj/MainMenu.nib/designable.nib | 936 +++++++++++++++--- .../MainMenu.nib/keyedobjects.nib | Bin 14553 -> 21074 bytes Tools/xcodecapp-cocoa/FSEventCallback.m | 31 +- Tools/xcodecapp-cocoa/TNXCodeCapp.h | 15 +- Tools/xcodecapp-cocoa/TNXCodeCapp.m | 179 +++- 7 files changed, 1000 insertions(+), 225 deletions(-) diff --git a/Tools/xcodecapp-cocoa/AppController.h b/Tools/xcodecapp-cocoa/AppController.h index 7e363729e..8e661090e 100644 --- a/Tools/xcodecapp-cocoa/AppController.h +++ b/Tools/xcodecapp-cocoa/AppController.h @@ -23,22 +23,26 @@ @interface AppController : NSObject { - IBOutlet NSMenu *statusMenu; - IBOutlet NSMenuItem *menuItemOpenXCode; - IBOutlet NSMenuItem *menuItemStartStop; - IBOutlet NSPanel *errorsPanel; - IBOutlet NSTableView *errorsTable; - IBOutlet NSPanel *aboutWindow; - IBOutlet NSWindow *helpWindow; - IBOutlet NSTextView *helpTextView; - IBOutlet NSTextField *labelVersion; - - TNXCodeCapp *xcc; - NSImage *_iconActive; - NSImage *_iconInactive; - NSImage *_iconWorking; - NSStatusItem *_statusItem; - PRHEmptyGrowlDelegate *growlDelegateRef; + IBOutlet NSMenu *statusMenu; + IBOutlet NSMenuItem *menuItemOpenXCode; + IBOutlet NSMenuItem *menuItemStartStop; + IBOutlet NSPanel *errorsPanel; + IBOutlet NSTableView *errorsTable; + IBOutlet NSPanel *aboutWindow; + IBOutlet NSWindow *helpWindow; + IBOutlet NSTextView *helpTextView; + IBOutlet NSTextField *labelVersion; + IBOutlet NSPopUpButton *buttonPreferencesAPIMode; + IBOutlet NSButton *checkBoxPreferencesReactMode; + IBOutlet NSUserDefaultsController *preferencesController; + IBOutlet TNXCodeCapp *xcc; + IBOutlet NSWindow *preferencesWindow; + + NSImage *_iconActive; + NSImage *_iconInactive; + NSImage *_iconWorking; + NSStatusItem *_statusItem; + PRHEmptyGrowlDelegate *growlDelegateRef; } @property BOOL supportsFileModeListening; @@ -59,6 +63,7 @@ - (IBAction)stopListener:(id)aSender; - (IBAction)openHelp:(id)aSender; - (IBAction)openAbout:(id)aSender; +- (IBAction)updatePreferences:(id)aSender; - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(int)aRow; - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; diff --git a/Tools/xcodecapp-cocoa/AppController.m b/Tools/xcodecapp-cocoa/AppController.m index 70221e6f2..370a87b21 100644 --- a/Tools/xcodecapp-cocoa/AppController.m +++ b/Tools/xcodecapp-cocoa/AppController.m @@ -75,8 +75,7 @@ AppController *SharedAppControllerInstance = nil; [[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithInt:0] forKey:@"FirstLaunch"]; [self openHelp:self]; } - - xcc = [[TNXCodeCapp alloc] init]; + [xcc setDelegate:self]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(XCodeCappConversionDidStart:) name:XCCConversionStartNotification object:xcc]; @@ -101,6 +100,9 @@ AppController *SharedAppControllerInstance = nil; [appDefaults setObject:streamEventIdSinceNow forKey:@"lastEventId"]; [appDefaults setObject:[NSNumber numberWithInt:1] forKey:@"FirstLaunch"]; + [appDefaults setObject:[NSNumber numberWithInt:0] forKey:@"XCCAPIMode"]; + [appDefaults setObject:[NSNumber numberWithInt:1] forKey:@"XCCReactMode"]; + [appDefaults setObject:[NSNumber numberWithInt:1] forKey:@"XCCReopenLastProject"]; [defaults registerDefaults:appDefaults]; } @@ -185,6 +187,18 @@ AppController *SharedAppControllerInstance = nil; #pragma mark - #pragma mark Actions +/*! + Save preferences + @param aSender the sender of the action + */ +- (IBAction)updatePreferences:(id)aSender +{ + [preferencesController save:aSender]; + NSLog(@"Preferences change notified"); + + [xcc configure]; +} + /*! Open the folder chooser and eventually start to listen @param aSender the sender of the action @@ -284,6 +298,15 @@ AppController *SharedAppControllerInstance = nil; [self openCenteredWindow:aboutWindow]; } +/*! + Open the preferences window + @param aSender the sender of the action + */ +- (IBAction)openPreferences:(id)aSender +{ + [self openCenteredWindow:preferencesWindow]; +} + /*! Open a centered window. */ diff --git a/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/designable.nib b/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/designable.nib index bc6963aa9..d8640f623 100644 --- a/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/designable.nib +++ b/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/designable.nib @@ -2,16 +2,19 @@ 1050 - 10K549 - 1923 - 1038.36 - 461.00 + 11C74 + 1938 + 1138.23 + 567.00 com.apple.InterfaceBuilder.CocoaPlugin - 1923 + 1938 + NSPopUpButtonCell + NSUserDefaultsController NSScroller + NSPopUpButton NSMenuItem NSMenu NSScrollView @@ -54,6 +57,7 @@ About NSPanel + 256 @@ -112,8 +116,9 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ {375, 153} - {{0, 0}, {1600, 1178}} - {1e+13, 1e+13} + {{0, 0}, {1680, 1028}} + {10000000000000, 10000000000000} + YES @@ -159,6 +164,24 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ + + Preferences + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + + About... @@ -202,6 +225,7 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ Errors and Warnings NSPanel + 256 @@ -256,7 +280,7 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ 337772032 0 Text Cell - + LucidaGrande 13 1044 @@ -268,7 +292,7 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ controlBackgroundColor - + 6 System controlTextColor @@ -296,6 +320,7 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ 0 YES 0 + 1 {{1, 1}, {512, 249}} @@ -330,7 +355,7 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ {{-1, 35}, {514, 251}} - 562 + 133682 @@ -385,8 +410,9 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ {512, 285} - {{0, 0}, {1600, 1178}} - {1e+13, 1e+13} + {{0, 0}, {1680, 1028}} + {10000000000000, 10000000000000} + YES 15 @@ -396,8 +422,9 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ Help NSWindow + - + 256 @@ -413,8 +440,7 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ 2322 {701, 14} - - + @@ -434,7 +460,7 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ 1 - 11525 + 67120389 0 @@ -465,16 +491,17 @@ bgphcGFyYWppdGFAYXBhcmFqaXRhLmNvbQ + + 1 6 - {716, 1e+07} + {716, 10000000} {238, 0} {{1, 1}, {701, 571}} - @@ -509,8 +536,6 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 256 {{702, 1}, {15, 571}} - - _doScroller: 1 @@ -521,7 +546,6 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA -2147483392 {{-100, -100}, {87, 18}} - 1 @@ -532,21 +556,299 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA {{-1, -1}, {718, 573}} - - - 18 + + 133138 {716, 571} - - - {{0, 0}, {1600, 1178}} - {1e+13, 1e+13} + {{0, 0}, {1680, 1028}} + {10000000000000, 10000000000000} + YES + + + 3 + 2 + {{529, 541}, {478, 265}} + 1685586944 + Preferences + NSWindow + + + + + 256 + + + + 269 + {{128, 64}, {234, 18}} + + + YES + + -2080244224 + 0 + Inode meta informations changes + + + 1211912703 + 2 + + NSImage + NSSwitch + + + NSSwitch + + + + 200 + 25 + + + + + 269 + {{127, 121}, {120, 26}} + + + YES + + -2076049856 + 2048 + + + 109199615 + 129 + + + 400 + 75 + + + Auto + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + OtherViews + + + + + File level + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Folder level + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + + 1 + YES + YES + 2 + + + + + 268 + {{17, 223}, {128, 22}} + + + YES + + 67239424 + 272629760 + Preferences + + LucidaGrande + 18 + 16 + + + + + 1 + MC4zNDU1Mjg0ODM0IDAuMzQ1NTI4NDgzNCAwLjM0NTUyODQ4MzQAA + + + + + + 269 + {{58, 65}, {60, 17}} + + + YES + + 68288064 + 272630784 + React to: + + + + + + + + + 269 + {{51, 153}, {67, 17}} + + + YES + + 68288064 + 272630784 + API Mode: + + + + + + + + + 269 + {{127, 153}, {184, 17}} + + + YES + + 68288064 + 272630784 + Current API Mode + + + + + + + + + 269 + {{127, 41}, {303, 17}} + + + YES + + 68288064 + 272630784 + On file "File Level", it will react to touch, or chown, etc. + + LucidaGrande + 11 + 16 + + + + + + + + + 269 + {{128, 182}, {176, 18}} + + + YES + + -2080244224 + 0 + Listen to the last project + + + 1211912703 + 2 + + + + + 200 + 25 + + + + + 269 + {{42, 183}, {76, 17}} + + + YES + + 68288064 + 272630784 + On Launch: + + + + + + + + + 269 + {{127, 90}, {301, 28}} + + + YES + + 68288064 + 272630784 + RmlsZSBtb2RlIGlzIG5vdCBjb21wYXRpYmxlIHdpdGggT1MgWCAxMC42LgpVbmxlc3MgeW91IGtub3cg +d2hhdCB5b3UgZG8sIGxlYXZlIHRoaXMgdG8gIkF1dG8iLg + + + + + 1 + MC4zNDU1Mjg0ODM0IDAuMzQ1NTI4NDgzNCAwLjM0NTUyODQ4MzQAA + + + + + {478, 265} + + + + {{0, 0}, {1680, 1028}} + {10000000000000, 10000000000000} + xcc-prefs + YES + + + YES + + + TNXCodeCapp @@ -655,14 +957,6 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 525 - - - openAbout: - - - - 526 - openErrors: @@ -671,14 +965,6 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 527 - - - menuItemStart - - - - 528 - menuItemStartStop @@ -695,6 +981,78 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 540 + + + openAbout: + + + + 571 + + + + buttonPreferencesAPIMode + + + + 573 + + + + checkBoxPreferencesReactMode + + + + 574 + + + + updatePreferences: + + + + 600 + + + + updatePreferences: + + + + 601 + + + + preferencesController + + + + 602 + + + + xcc + + + + 611 + + + + openPreferences: + + + + 646 + + + + preferencesWindow + + + + 647 + performClose: @@ -719,6 +1077,152 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA 478 + + + value: values.XCCReactMode + + + + + + value: values.XCCReactMode + value + values.XCCReactMode + + NSValidatesImmediately + + + 2 + + + 594 + + + + enabled: isUsingFileLevelAPI + + + + + + enabled: isUsingFileLevelAPI + enabled + isUsingFileLevelAPI + 2 + + + 641 + + + + selectedIndex: values.XCCAPIMode + + + + + + selectedIndex: values.XCCAPIMode + selectedIndex + values.XCCAPIMode + + NSValidatesImmediately + + + 2 + + + 605 + + + + enabled: supportFileLevelAPI + + + + + + enabled: supportFileLevelAPI + enabled + supportFileLevelAPI + + + + + + + 2 + + + 642 + + + + enabled2: isListening + + + + + + enabled2: isListening + enabled2 + isListening + + + + + + NSNegateBoolean + + + 2 + + + 645 + + + + save: + + + + 658 + + + + value: currentAPIMode + + + + + + value: currentAPIMode + value + currentAPIMode + 2 + + + 615 + + + + value: values.XCCReopenLastProject + + + + + + value: values.XCCReopenLastProject + value + values.XCCReopenLastProject + + NSValidatesImmediately + + + 2 + + + 657 + @@ -787,12 +1291,14 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA - + + + @@ -975,6 +1481,209 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA + + 541 + + + + + + + + 542 + + + + + + + + + + + + + + + + + 543 + + + + + + + + 544 + + + + + 545 + + + + + + + + 546 + + + + + + + + 547 + + + + + + + + + + 548 + + + + + 549 + + + + + 550 + + + + + 551 + + + + + + + + 552 + + + + + 553 + + + + + + + + 554 + + + + + 555 + + + + + + + + 556 + + + + + 557 + + + + + + + + 558 + + + + + 559 + + + + + + + + 560 + + + + + 569 + + + + + 570 + + + + + 587 + + + + + 608 + + + + + + + + 609 + + + + + 610 + + + + + 648 + + + + + + + + 649 + + + + + + + + 652 + + + + + 653 + + + @@ -1020,113 +1729,47 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + + + com.apple.InterfaceBuilder.CocoaPlugin + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin - 540 - - - - - AppController - NSObject - - id - id - id - id - id - id - id - - - - chooseFolder: - id - - - clearErrors: - id - - - openAbout: - id - - - openErrors: - id - - - openHelp: - id - - - openXCode: - id - - - stopListener: - id - - - - NSPanel - NSPanel - NSTableView - NSTextView - NSWindow - NSTextField - NSMenuItem - NSMenuItem - NSMenu - - - - aboutWindow - NSPanel - - - errorsPanel - NSPanel - - - errorsTable - NSTableView - - - helpTextView - NSTextView - - - helpWindow - NSWindow - - - labelVersion - NSTextField - - - menuItemOpenXCode - NSMenuItem - - - menuItemStartStop - NSMenuItem - - - statusMenu - NSMenu - - - - IBProjectSource - ./Classes/AppController.h - - - + 658 + 0 IBCocoaFramework @@ -1142,6 +1785,7 @@ AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA {9, 8} {7, 2} + {15, 15} diff --git a/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/keyedobjects.nib b/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/keyedobjects.nib index 2df780f1a097e48fdbee840aac728b8822988523..342a7406a141f170504066cea32ae91807c4d92c 100644 GIT binary patch literal 21074 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 PEx()u``_l@9aR4deWhPA literal 14553 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 10 && versionMinor >= 7; - // Uncomment to test under 10.7 - // supportsFileBasedListening = NO; - - if (supportsFileBasedListening) - DLog(@"using 10.7+ mode listening (clean)"); - else - DLog(@"using 10.6 mode listening (dirty)"); + [self setSupportFileLevelAPI:versionMajor >= 10 && versionMinor >= 7]; + // Uncomment to simulate 10.6 mode + //[self setSupportFileLevelAPI:NO]; + [self configure]; + if([fm fileExistsAtPath:[@"~/.bash_profile" stringByExpandingTildeInPath]]) profilePath = [@"source ~/.bash_profile" stringByExpandingTildeInPath]; else if([fm fileExistsAtPath:[@"~/.profile" stringByExpandingTildeInPath]]) @@ -89,6 +97,9 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification - (void)start { + if (![[NSUserDefaults standardUserDefaults] boolForKey:@"XCCReopenLastProject"]) + return; + NSString *lastOpenedPath = [[NSUserDefaults standardUserDefaults] objectForKey:@"LastOpenedPath"]; if (lastOpenedPath) @@ -135,8 +146,13 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); FSEventStreamStart(stream); + [self setIsListening:YES]; } + +#pragma mark - +#pragma mark Utilities + /*! Stop listening the FSEvent stream if active */ @@ -148,6 +164,8 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification FSEventStreamInvalidate(stream); stream = nil; } + + [self setIsListening:NO]; } /*! @@ -161,9 +179,46 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification [self stopEventStream]; } +/*! + Choose the API mode according to default + */ +- (void)configure +{ + if (![self supportFileLevelAPI]) + { + DLog(@"System doesn't support file level API"); + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInt:2] forKey:@"XCCAPIMode"]; + } -#pragma mark - -#pragma mark Utilities + switch ([[NSUserDefaults standardUserDefaults] integerForKey:@"XCCAPIMode"]) + { + case 0: + supportsFileBasedListening = [self supportFileLevelAPI] ? YES : NO; + break; + case 1: + supportsFileBasedListening = YES; + break; + case 2: + supportsFileBasedListening = NO; + break; + } + + if (supportsFileBasedListening) + { + DLog(@"using 10.7+ mode listening (clean)"); + + [self setCurrentAPIMode:@"File level (Lion)"]; + [self setIsUsingFileLevelAPI:YES]; + reactToInodeModification = [[NSUserDefaults standardUserDefaults] boolForKey:@"XCCReactMode"]; + } + else + { + DLog(@"using 10.6 mode listening (dirty)"); + reactToInodeModification = NO; + [self setCurrentAPIMode:@"Folder level (Snow Leopard)"]; + [self setIsUsingFileLevelAPI:NO]; + } +} /*! Update the last event ID. We use a method because @@ -398,12 +453,16 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification { [delegate performSelector:@selector(growlWithTitle:message:) withObject:@"Loading project" withObject:[currentProjectURL path]]; - [self handleFileModification:[NSString stringWithFormat:@"%@", [currentProjectURL path]] notify:NO]; - NSArray *subdirs = [fm subpathsAtPath:[currentProjectURL path]]; - - for (NSString *p in subdirs) - [self handleFileModification:[NSString stringWithFormat:@"%@/%@", [currentProjectURL path], p] notify:NO]; + //[self handleFileModification:[NSString stringWithFormat:@"%@", [currentProjectURL path]] notify:NO]; + NSArray *subdpaths = [fm subpathsAtPath:[currentProjectURL path]]; + for (NSString *p in subdpaths) + { + NSString *filePath = [NSString stringWithFormat:@"%@/%@", [currentProjectURL path], p]; + DLog(@"Original import of %@", filePath); + [self handleFileModification:filePath notify:NO]; + } + NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:currentProjectURL, @"URL", nil]; [[NSNotificationCenter defaultCenter] postNotificationName:XCCDidPopulateProjectNotification object:self userInfo:info]; } @@ -413,12 +472,17 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification @param aSourceURL the origin path @return NSURL representing the shadow path */ -- (NSURL*)shadowURLForSourceURL:(NSURL*)aSourceURL +- (NSURL *)shadowURLForSourceURL:(NSURL*)aSourceURL { if (!aSourceURL) [NSException raise:NSInvalidArgumentException format:@"shadowURLForSourceURL: aSource URL must not be null"]; NSMutableString *flattenedPath = [NSMutableString stringWithString:[aSourceURL path]]; + [flattenedPath replaceOccurrencesOfString:@"_" + withString:@"-OLDUNDERSCORE-" + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [[aSourceURL path] length])]; + [flattenedPath replaceOccurrencesOfString:@"/" withString:@"_" options:NSCaseInsensitiveSearch @@ -430,6 +494,29 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification return [NSURL URLWithString:basename relativeToURL:XCodeSupportProjectSources]; } +- (NSURL *)sourceURLForShadowName:(NSString *)aString +{ + NSMutableString * unshadowedPath = [NSMutableString stringWithString:aString]; + + [unshadowedPath replaceOccurrencesOfString:@"_" + withString:@"/" + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [unshadowedPath length])]; + + [unshadowedPath replaceOccurrencesOfString:@"-OLDUNDERSCORE-" + withString:@"_" + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [unshadowedPath length])]; + + [unshadowedPath replaceOccurrencesOfString:@".h" + withString:@".j" + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [unshadowedPath length])]; + + return [NSURL URLWithString:[NSString stringWithString:unshadowedPath]]; +} + + /*! Compute the ignored paths according to any existing .xcodecapp-ignore file @@ -438,12 +525,12 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification { NSString *ignorePath = [NSString stringWithFormat:@"%@/.xcodecapp-ignore", [currentProjectURL path]]; [ignoredFilePaths removeAllObjects]; - + if ([fm fileExistsAtPath:ignorePath]) { NSString *ignoreFileContent = [NSString stringWithContentsOfFile:ignorePath encoding:NSUTF8StringEncoding error:nil]; NSArray *ignoredPatterns = [ignoreFileContent componentsSeparatedByString:@"\n"]; - + for (NSString *pattern in ignoredPatterns) { if ([pattern length]) @@ -531,6 +618,28 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification [[NSUserDefaults standardUserDefaults] setObject:[currentProjectURL path] forKey:@"LastOpenedPath"]; } +/*! + Clean the support folder according to files present in given path + @param basePath the path of the folder to check + */ +- (void)tidyShadowedFiles:(NSString*)basePath +{ + NSArray *subpaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[XCodeSupportProjectSources path] error:NULL]; + + for (NSString *subpath in subpaths) + { + NSString *unshadowed = [[self sourceURLForShadowName:subpath] path]; + NSString *shadowFullPath = [NSString stringWithFormat:@"%@/%@", [XCodeSupportProjectSources path], subpath]; + if (![fm fileExistsAtPath:unshadowed]) + { + DLog(@"cleaning shadow file: %@", subpath); + [fm removeItemAtPath:shadowFullPath error:nil]; + if (![self supportFileLevelAPI] && [self respondsToSelector:@selector(updateLastModificationDate:forPath:)]) + [self performSelector:@selector(updateLastModificationDate:forPath:) withObject:nil withObject:unshadowed]; + } + } +} + @end @@ -570,38 +679,4 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification return appStartedTimestamp; } -- (NSString *)unshadowURLForString:(NSString *)aString -{ - NSMutableString * unshadowedPath = [NSMutableString stringWithString:aString]; - - [unshadowedPath replaceOccurrencesOfString:@"_" - withString:@"/" - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [unshadowedPath length])]; - - [unshadowedPath replaceOccurrencesOfString:@".h" - withString:@".j" - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [unshadowedPath length])]; - - return [NSString stringWithString:unshadowedPath]; -} - -- (void)tidyShadowedFiles:(NSString*)basePath -{ - NSArray *subpaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[XCodeSupportProjectSources path] error:NULL]; - - for (NSString *subpath in subpaths) - { - NSString *unshadowed = [self unshadowURLForString:subpath]; - NSString *shadowFullPath = [NSString stringWithFormat:@"%@/%@", [XCodeSupportProjectSources path], subpath]; - if (![fm fileExistsAtPath:unshadowed]) - { - DLog(@"cleaning shadow file: %@", subpath); - [fm removeItemAtPath:shadowFullPath error:nil]; - [self updateLastModificationDate:nil forPath:unshadowed]; - } - } -} - @end