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 2df780f1a..342a7406a 100644 Binary files a/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/keyedobjects.nib and b/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/keyedobjects.nib differ diff --git a/Tools/xcodecapp-cocoa/FSEventCallback.m b/Tools/xcodecapp-cocoa/FSEventCallback.m index 7de6a5e2a..8577badd6 100644 --- a/Tools/xcodecapp-cocoa/FSEventCallback.m +++ b/Tools/xcodecapp-cocoa/FSEventCallback.m @@ -38,9 +38,19 @@ void fsevents_callback(ConstFSEventStreamRef streamRef, for (i = 0; i < numEvents; i++) { NSString *path = [[(NSArray *)eventPaths objectAtIndex:i] stringByStandardizingPath]; + BOOL isDir = NO; + + [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir]; if (useFileBasedListening) { + // kFSEventStreamEventFlagItemIsFile = 0x00010000 + // kFSEventStreamEventFlagItemRemoved = 0x00000200 + if (eventFlags[i] & 0x00010000 && eventFlags[i] & 0x00000200) + { + [xcc tidyShadowedFiles:path]; + } + // kFSEventStreamEventFlagItemIsFile = 0x00010000 if (!(eventFlags[i] & 0x00010000) || [xcc isPathMatchingIgnoredPaths:path] @@ -55,9 +65,17 @@ void fsevents_callback(ConstFSEventStreamRef streamRef, } // kFSEventStreamEventFlagItemCreated = 0x00000200 - if (eventFlags[i] & 0x00000100) + // kFSEventStreamEventFlagItemModified = 0x00001000 + if (eventFlags[i] & 0x00000100 || eventFlags[i] & 0x00001000) { - DLog(@"event type: kFSEventStreamEventFlagItemCreated for path %@", path); + DLog(@"event type: kFSEventStreamEventFlagItemCreated or kFSEventStreamEventFlagItemModified for path %@", path); + [xcc handleFileModification:path notify:YES]; + } + + // kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400 + if (eventFlags[i] & 0x00000400 && [xcc reactToInodeModification]) + { + DLog(@"event type: kFSEventStreamEventFlagItemInodeMetaMod for path %@", path); [xcc handleFileModification:path notify:YES]; } @@ -80,11 +98,10 @@ void fsevents_callback(ConstFSEventStreamRef streamRef, { NSArray *subpaths = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL]; - // Uncomment to test under 10.7 - // BOOL isDir; - // [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir]; - // if (!isDir) - // continue; + // If for some reasons the path is not a directory, + // we don't want to deal with it in this mode. + if (!isDir) + continue; [xcc tidyShadowedFiles:path]; diff --git a/Tools/xcodecapp-cocoa/TNXCodeCapp.h b/Tools/xcodecapp-cocoa/TNXCodeCapp.h index 0f9bb7297..f196de030 100644 --- a/Tools/xcodecapp-cocoa/TNXCodeCapp.h +++ b/Tools/xcodecapp-cocoa/TNXCodeCapp.h @@ -33,6 +33,7 @@ extern NSString * const XCCListeningStartNotification; NSMutableArray *errorList; NSMutableSet *ignoredFilePaths; NSNumber *lastEventId; + NSString *currentAPIMode; NSString *currentProjectName; NSString *parserPath; NSString *XCodeSupportPBXPath; @@ -48,6 +49,10 @@ extern NSString * const XCCListeningStartNotification; NSDate *appStartedTimestamp; NSMutableDictionary *pathModificationDates; BOOL supportsFileBasedListening; + BOOL reactToInodeModification; + BOOL isListening; + BOOL isUsingFileLevelAPI; + BOOL supportFileLevelAPI; } @property (retain) NSObject* delegate; @@ -55,7 +60,12 @@ extern NSString * const XCCListeningStartNotification; @property (retain) NSURL* XCodeSupportProject; @property (retain) NSURL* currentProjectURL; @property (retain) NSString* currentProjectName; +@property (retain) NSString* currentAPIMode; @property BOOL supportsFileBasedListening; +@property BOOL reactToInodeModification; +@property BOOL isListening; +@property BOOL supportFileLevelAPI; +@property BOOL isUsingFileLevelAPI; - (BOOL)isObjJFile:(NSString*)path; - (void)computeIgnoredPaths; @@ -64,6 +74,7 @@ extern NSString * const XCCListeningStartNotification; - (BOOL)isXCCIgnoreFile:(NSString *)path; - (BOOL)prepareXCodeSupportProject; - (NSURL*)shadowURLForSourceURL:(NSURL*)aSourceURL; +- (NSURL*)sourceURLForShadowName:(NSString *)aString; - (void)handleFileModification:(NSString*)fullPath notify:(BOOL)shouldNotify; - (void)handleFileRemoval:(NSString*)fullPath; - (void)initializeEventStreamWithPath:(NSString*)aPath; @@ -72,6 +83,8 @@ extern NSString * const XCCListeningStartNotification; - (void)listenProjectAtPath:(NSString *)path; - (void)clear; - (void)start; +- (void)configure; +- (void)tidyShadowedFiles:(NSString*)basePath; @end @@ -80,8 +93,6 @@ extern NSString * const XCCListeningStartNotification; - (void)updateLastModificationDate:(NSDate *)date forPath:(NSString *)path; - (NSDate*)lastModificationDateForPath:(NSString *)path; -- (NSString *)unshadowURLForString:(NSString *)aString; -- (void)tidyShadowedFiles:(NSString*)basePath; @end diff --git a/Tools/xcodecapp-cocoa/TNXCodeCapp.m b/Tools/xcodecapp-cocoa/TNXCodeCapp.m index 24f2d3a91..cdae5eaf8 100644 --- a/Tools/xcodecapp-cocoa/TNXCodeCapp.m +++ b/Tools/xcodecapp-cocoa/TNXCodeCapp.m @@ -33,6 +33,14 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification @synthesize currentProjectURL; @synthesize currentProjectName; @synthesize supportsFileBasedListening; +@synthesize reactToInodeModification; +@synthesize currentAPIMode; +@synthesize isListening; +@synthesize supportFileLevelAPI; +@synthesize isUsingFileLevelAPI; + +#pragma mark - +#pragma mark Initialization /*! Initialize the AppController @@ -50,20 +58,20 @@ NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification lastEventId = [[NSUserDefaults standardUserDefaults] objectForKey:@"lastEventId"]; appStartedTimestamp = [NSDate date]; + [self setIsListening:NO]; + [self setIsUsingFileLevelAPI:NO]; + SInt32 versionMajor = 0; SInt32 versionMinor = 0; Gestalt(gestaltSystemVersionMajor, &versionMajor); Gestalt(gestaltSystemVersionMinor, &versionMinor); - supportsFileBasedListening = versionMajor >= 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