diff --git a/Tests/Manual/CPScrollView2/.xCodeSupport/scrollview.xcodeproj/project.pbxproj b/Tests/Manual/CPScrollView2/.xCodeSupport/scrollview.xcodeproj/project.pbxproj index 2760e2941..83d2420fc 100644 --- a/Tests/Manual/CPScrollView2/.xCodeSupport/scrollview.xcodeproj/project.pbxproj +++ b/Tests/Manual/CPScrollView2/.xCodeSupport/scrollview.xcodeproj/project.pbxproj @@ -134,9 +134,10 @@ 9EEC448A135749D200615446 /* Project object */ = { isa = PBXProject; attributes = { + LastUpgradeCheck = 0420; ORGANIZATIONNAME = "280 North, Inc."; }; - buildConfigurationList = 9EEC448D135749D200615446 /* Build configuration list for PBXProject "Another" */; + buildConfigurationList = 9EEC448D135749D200615446 /* Build configuration list for PBXProject "scrollview" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -323,7 +324,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 9EEC448D135749D200615446 /* Build configuration list for PBXProject "Another" */ = { + 9EEC448D135749D200615446 /* Build configuration list for PBXProject "scrollview" */ = { isa = XCConfigurationList; buildConfigurations = ( 9EEC44C3135749D300615446 /* Debug */, @@ -339,6 +340,7 @@ 9EEC44C7135749D300615446 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 9EEC44C8135749D300615446 /* Build configuration list for PBXNativeTarget "AnotherTests" */ = { isa = XCConfigurationList; @@ -347,6 +349,7 @@ 9EEC44CA135749D300615446 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Tests/Manual/NibAppRemixed/.xCodeSupport/NibAppRemixed.xcodeproj/project.pbxproj b/Tests/Manual/NibAppRemixed/.xCodeSupport/NibAppRemixed.xcodeproj/project.pbxproj index 508461eac..0c00d2009 100644 --- a/Tests/Manual/NibAppRemixed/.xCodeSupport/NibAppRemixed.xcodeproj/project.pbxproj +++ b/Tests/Manual/NibAppRemixed/.xCodeSupport/NibAppRemixed.xcodeproj/project.pbxproj @@ -134,9 +134,10 @@ 9EEC448A135749D200615446 /* Project object */ = { isa = PBXProject; attributes = { + LastUpgradeCheck = 0420; ORGANIZATIONNAME = "280 North, Inc."; }; - buildConfigurationList = 9EEC448D135749D200615446 /* Build configuration list for PBXProject "Another" */; + buildConfigurationList = 9EEC448D135749D200615446 /* Build configuration list for PBXProject "NibAppRemixed" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -323,7 +324,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 9EEC448D135749D200615446 /* Build configuration list for PBXProject "Another" */ = { + 9EEC448D135749D200615446 /* Build configuration list for PBXProject "NibAppRemixed" */ = { isa = XCConfigurationList; buildConfigurations = ( 9EEC44C3135749D300615446 /* Debug */, @@ -339,6 +340,7 @@ 9EEC44C7135749D300615446 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; 9EEC44C8135749D300615446 /* Build configuration list for PBXNativeTarget "AnotherTests" */ = { isa = XCConfigurationList; @@ -347,6 +349,7 @@ 9EEC44CA135749D300615446 /* Release */, ); defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; diff --git a/Tools/xcodecapp-cocoa/AppController.h b/Tools/xcodecapp-cocoa/AppController.h index 9a8fb6d55..0257b9af5 100644 --- a/Tools/xcodecapp-cocoa/AppController.h +++ b/Tools/xcodecapp-cocoa/AppController.h @@ -17,67 +17,42 @@ */ #import +#import #import "PRHEmptyGrowlDelegate.h" +#import "TNXCodeCapp.h" @interface AppController : NSObject { - IBOutlet NSButton *buttonOpenXCode; - IBOutlet NSButton *buttonStart; - IBOutlet NSButton *buttonStop; IBOutlet NSMenu *statusMenu; IBOutlet NSMenuItem *menuItemOpenXCode; IBOutlet NSMenuItem *menuItemStart; IBOutlet NSMenuItem *menuItemStop; + IBOutlet NSMenuItem *menuItemProjectName; IBOutlet NSPanel *errorsPanel; - IBOutlet NSProgressIndicator *spinner; IBOutlet NSTableView *errorsTable; - IBOutlet NSTextField *labelCurrentPath; - IBOutlet NSTextField *labelPath; - IBOutlet NSTextField *labelStatus; - IBOutlet NSWindow *mainWindow; + IBOutlet NSWindow *helpWindow; + IBOutlet NSTextView *helpTextView; + IBOutlet NSTextField *labelVersion; - FSEventStreamRef stream; - NSDate *appStartedTimestamp; - NSFileManager *fm; + TNXCodeCapp *_xcc; NSImage *_iconActive; NSImage *_iconInactive; - NSMutableArray *errorList; - NSMutableArray *ignoredFilePaths; - NSMutableArray *modifiedXIBs; - NSMutableDictionary *pathModificationDates; - NSNumber *lastEventId; + NSImage *_iconWorking; NSStatusItem *_statusItem; - NSString *currentProjectName; - NSString *parserPath; - NSString *XCodeSupportPBXPath; - NSString *XCodeSupportProjectName; - NSString *XCodeTemplatePBXPath; - NSString *_profilePath; - NSURL *currentProjectURL; - NSURL *XCodeSupportFolder; - NSURL *XCodeSupportProject; - NSURL *XCodeSupportProjectSources; PRHEmptyGrowlDelegate *growlDelegateRef; } -- (BOOL)isObjJFile:(NSString*)path; -- (BOOL)isPathMatchingIgnoredPaths:(NSString*)aPath; -- (BOOL)isXIBFile:(NSString *)path; -- (BOOL)prepareXCodeSupportProject; - (BOOL)validateMenuItem:(NSMenuItem*)menuItem; -- (NSURL*)shadowURLForSourceURL:(NSURL*)aSourceURL; -- (void)handleFileModification:(NSString*)path ignoreDate:(BOOL)shouldIgnoreDate; -- (void)initializeEventStreamWithPath:(NSString*)aPath; - (void)registerDefaults; - (void)updateErrorTable; -- (void)updateLastEventId:(uint64_t)eventId; +- (void)growlWithTitle:(NSString *)aTitle message:(NSString *)aMessage; - (IBAction)chooseFolder:(id)aSender; - (IBAction)clearErrors:(id)sender; - (IBAction)openXCode:(id)aSender; - (IBAction)stopListener:(id)aSender; +- (IBAction)openHelp:(id)aSender; -- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag; - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(int)aRow; - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row; - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView; diff --git a/Tools/xcodecapp-cocoa/AppController.m b/Tools/xcodecapp-cocoa/AppController.m index 2eed110d1..5fef5c165 100644 --- a/Tools/xcodecapp-cocoa/AppController.m +++ b/Tools/xcodecapp-cocoa/AppController.m @@ -19,122 +19,71 @@ #import "AppController.h" -void fsevents_callback(ConstFSEventStreamRef streamRef, void *userData, size_t numEvents, - void *eventPaths, const FSEventStreamEventFlags eventFlags[], const FSEventStreamEventId eventIds[]) -{ - AppController *ac = (AppController *)userData; - size_t i; - for(i = 0; i < numEvents; i++) - { - [ac handleFileModification:[(NSArray *)eventPaths objectAtIndex:i] ignoreDate:NO]; - [ac updateLastEventId:eventIds[i]]; - } -} - - @implementation AppController #pragma mark - #pragma mark Initialization -- (id)init -{ - self = [super init]; - - if (self) - { - errorList = [NSMutableArray arrayWithCapacity:10]; - - if (!growlDelegateRef) - growlDelegateRef = [[[PRHEmptyGrowlDelegate alloc] init] autorelease]; - - [GrowlApplicationBridge setGrowlDelegate:growlDelegateRef]; - - fm = [NSFileManager defaultManager]; - modifiedXIBs = [NSMutableArray new]; - ignoredFilePaths = [NSMutableArray new]; - parserPath = [[NSBundle mainBundle] pathForResource:@"parser" ofType:@"j"]; - - if([fm fileExistsAtPath:[@"~/.bash_profile" stringByExpandingTildeInPath]]) - _profilePath = [@"source ~/.bash_profile" stringByExpandingTildeInPath]; - else if([fm fileExistsAtPath:[@"~/.profile" stringByExpandingTildeInPath]]) - _profilePath = [@"source ~/.profile" stringByExpandingTildeInPath]; - else if([fm fileExistsAtPath:[@"~/.bashrc" stringByExpandingTildeInPath]]) - _profilePath = [@"source ~/.bashrc" stringByExpandingTildeInPath]; - else if([fm fileExistsAtPath:[@"~/.zshrc" stringByExpandingTildeInPath]]) - _profilePath = [@"source ~/.zshrc" stringByExpandingTildeInPath]; - else - { - NSAlert *alert = [NSAlert alertWithMessageText:@"Cannot find any valid profile file" - defaultButton:@"Ok" - alternateButton:nil - otherButton:nil - informativeTextWithFormat:@"We have checked for ~/.bash_profile, ~/.profile, ~/.bashrc and ~/.zshrc without luck.\n\nYou need to have on of this file to tell XCodeCapp-cocoa where is located nib2cib. Now we gonna try to without sourcing one this file and it may fail.\n\nIf you notice any error or weird behaviour, please look at Mac OS' Console.app for log message and open a ticket."]; - [alert runModal]; - _profilePath = @""; - } - } - - return self; -} - +/*! + Called when NIB is ready + */ - (void)awakeFromNib { - [self registerDefaults]; - [labelCurrentPath setHidden:YES]; - [buttonOpenXCode setEnabled:NO]; - [buttonStop setEnabled:NO]; - [buttonStart setEnabled:YES]; - [spinner setHidden:YES]; - appStartedTimestamp = [NSDate date]; - pathModificationDates = [[[NSUserDefaults standardUserDefaults] dictionaryForKey:@"pathModificationDates"] mutableCopy]; - lastEventId = [[NSUserDefaults standardUserDefaults] objectForKey:@"lastEventId"]; + if (!growlDelegateRef) + growlDelegateRef = [[[PRHEmptyGrowlDelegate alloc] init] autorelease]; + + [GrowlApplicationBridge setGrowlDelegate:growlDelegateRef]; NSBundle *bundle = [NSBundle mainBundle]; - _iconInactive = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"xcodecapp-cocoa-icon-inactive" ofType:@"png"]]; - _iconActive = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"xcodecapp-cocoa-icon-active" ofType:@"png"]]; + [labelVersion setStringValue:[NSString stringWithFormat:@"Version %@", [bundle objectForInfoDictionaryKey:@"CFBundleVersion"]]]; + + [self registerDefaults]; + + _iconInactive = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"xcodecapp-cocoa-icon-inactive" ofType:@"png"]]; + _iconActive = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"xcodecapp-cocoa-icon-active" ofType:@"png"]]; + _iconWorking = [[NSImage alloc] initWithContentsOfFile:[bundle pathForResource:@"xcodecapp-cocoa-icon-working" ofType:@"png"]]; [_iconActive setSize:NSMakeSize(14.0, 16.0)]; [_iconInactive setSize:NSMakeSize(14.0, 16.0)]; + [_iconWorking setSize:NSMakeSize(14.0, 16.0)]; _statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; [_statusItem setMenu:statusMenu]; [_statusItem setImage:_iconInactive]; [_statusItem setHighlightMode:YES]; [statusMenu setDelegate:self]; -} - -- (void)initializeEventStreamWithPath:(NSString*)aPath -{ - NSArray *pathsToWatch = [NSArray arrayWithObject:aPath]; - void *appPointer = (void *)self; - FSEventStreamContext context = {0, appPointer, NULL, NULL, NULL}; - NSTimeInterval latency = 5.0; - stream = FSEventStreamCreate(NULL, &fsevents_callback, &context, (CFArrayRef) pathsToWatch, - [lastEventId unsignedLongLongValue], (CFAbsoluteTime) latency,kFSEventStreamCreateFlagUseCFTypes); - - FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); - FSEventStreamStart(stream); -} - -- (void)stopEventStream -{ - if (stream) + if ([[NSUserDefaults standardUserDefaults] integerForKey:@"FirstLaunch"]) { - FSEventStreamStop(stream); - FSEventStreamInvalidate(stream); - stream = 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]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(XCodeCappConversionDidStop:) name:XCCConversionStopNotification object:_xcc]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(XCodeCappPopulateProject:) name:XCCDidPopulateProjectNotification object:_xcc]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(XCodeCappListeningDidStart:) name:XCCListeningStartNotification object:_xcc]; + + [_xcc start]; } + +/*! + Register the application defaults + */ - (void)registerDefaults { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - NSDictionary *appDefaults = [NSDictionary - dictionaryWithObjects:[NSArray arrayWithObjects:[NSNumber numberWithUnsignedLongLong:kFSEventStreamEventIdSinceNow], [NSMutableDictionary new], nil] - forKeys:[NSArray arrayWithObjects:@"lastEventId", @"pathModificationDates", nil]]; + NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; + NSNumber *streamEventIdSinceNow = [NSNumber numberWithUnsignedLongLong:kFSEventStreamEventIdSinceNow]; + NSMutableDictionary *appDefaults = [NSMutableDictionary new]; + + [appDefaults setObject:streamEventIdSinceNow forKey:@"lastEventId"]; + [appDefaults setObject:[NSNumber numberWithInt:1] forKey:@"FirstLaunch"]; + [defaults registerDefaults:appDefaults]; } @@ -142,289 +91,85 @@ void fsevents_callback(ConstFSEventStreamRef streamRef, void *userData, size_t n #pragma mark - #pragma mark Notification handlers -- (NSApplicationTerminateReply)applicationShouldTerminate: (NSApplication *)app +/*! + Handle cleaning operation when application will stop. + It will stop the FSEvent listener, and store the last event id + */ +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)app { - NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; - - [defaults setObject:lastEventId forKey:@"lastEventId"]; - [defaults setObject:pathModificationDates forKey:@"pathModificationDates"]; - [defaults synchronize]; - - [self stopEventStream]; + [_xcc clear]; return NSTerminateNow; } +/*! + Called when XCC start a conversion + @param aNotification the notification + */ +- (void)XCodeCappConversionDidStart:(NSNotification *)aNotification +{ + [_statusItem setImage:_iconWorking]; +} + +/*! + Called when XCC finish a conversion + @param aNotification the notification + */ +- (void)XCodeCappConversionDidStop:(NSNotification *)aNotification +{ + [_statusItem setImage:_iconActive]; +} + +/*! + Called when XCC has populated a project + @param aNotification the notification + */ +- (void)XCodeCappPopulateProject:(NSNotification *)aNotification +{ + [self growlWithTitle:[[[[aNotification userInfo] objectForKey:@"URL"] path] lastPathComponent] + message:@"Your project has been loaded successfully!"]; + +} + +/*! + Called when XCC start a to listen to a project + @param aNotification the notification + */ +- (void)XCodeCappListeningDidStart:(NSNotification *)aNotification +{ + [_statusItem setImage:_iconActive]; + [menuItemProjectName setTitle:[NSString stringWithFormat:@"Current project: %@", [_xcc currentProjectName]]]; +} + #pragma mark - #pragma mark Utilities -- (void)updateLastModificationDateForPath: (NSString *)path +/*! + Simple growl wrapper + @param aTitle the growl title + @param aMessage the growl message + */ +- (void)growlWithTitle:(NSString *)aTitle message:(NSString *)aMessage { - [pathModificationDates setObject:[NSDate date] forKey:path]; -} - -- (NSDate*)lastModificationDateForPath: (NSString *)path -{ - if(nil != [pathModificationDates valueForKey:path]) - return [pathModificationDates valueForKey:path]; - else - return appStartedTimestamp; -} - -- (void)updateLastEventId:(uint64_t)eventId -{ - lastEventId = [NSNumber numberWithUnsignedLongLong:eventId]; -} - -- (void)handleFileModification:(NSString*)path ignoreDate:(BOOL)shouldIgnoreDate -{ - if ([self isPathMatchingIgnoredPaths:path]) - return; - - NSArray *contents = [fm contentsOfDirectoryAtPath:path error:NULL]; - NSDate *lastModifiedDate = [self lastModificationDateForPath:path]; - - [self updateLastModificationDateForPath:path]; - for(NSString *node in contents) - { - NSString *fullPath = [NSString stringWithFormat:@"%@/%@", path, node]; - NSString *splitedPath = [NSString stringWithFormat:@"%@/%@", [[fullPath pathComponents] objectAtIndex:[[fullPath pathComponents] count] - 2], [fullPath lastPathComponent]]; - NSDictionary *fileAttributes = [fm attributesOfItemAtPath:fullPath error:NULL]; - NSDate *fileModDate = [fileAttributes objectForKey:NSFileModificationDate]; - - if(shouldIgnoreDate || [fileModDate compare:lastModifiedDate] == NSOrderedDescending) - { - //Prepare the shell - NSTask *task; - task = [[NSTask alloc] init]; - [task setLaunchPath: @"/bin/bash"]; - NSArray *arguments; - NSString *successMsg; - - if ([self isXIBFile:fullPath] || [self isObjJFile:fullPath]) - { - if ([self isXIBFile:fullPath]) - { - - NSLog(@"running command nib2cib %@", fullPath); - - //Create the nib2cib task - arguments = [NSArray arrayWithObjects: @"-c", - [NSString stringWithFormat:@"(%@; nib2cib '%@';) 2>&1", _profilePath, fullPath],@"",nil]; - successMsg = @"The XIB file has been converted"; - } - else if ([self isObjJFile:fullPath]) - { - NSLog(@"Full path string is: %@", [fullPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]); - NSString *shadowPath = [[self shadowURLForSourceURL:[NSURL URLWithString:[fullPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]] path]; - NSLog(@"running command objj %@", shadowPath); - //Create the objj task - arguments = [NSArray arrayWithObjects: @"-c", - [NSString stringWithFormat:@"(%@; objj '%@' '%@' '%@';) 2>&1", _profilePath, parserPath, fullPath, shadowPath],@"",nil]; - successMsg = @"The Objective-J file has been converted"; - } - - //Run the task and get the response - [task setArguments: arguments]; - [task setStandardOutput:[NSPipe pipe]]; - - [_statusItem setTitle:@"..."]; - [task launch]; - [task waitUntilExit]; - - NSData *stdOut; - stdOut = [[[task standardOutput] fileHandleForReading] availableData]; - NSString *response; - response = [[NSString alloc] initWithData:stdOut - encoding:NSUTF8StringEncoding]; - - NSLog(@"response was\n%@", response); - - [_statusItem setTitle:@""]; - if ([task terminationStatus] == 0) - { - if (!shouldIgnoreDate) - { - [GrowlApplicationBridge notifyWithTitle:splitedPath - description:successMsg - notificationName:@"DefaultNotifications" - iconData:nil - priority:0 - isSticky:NO - clickContext:nil]; - } - - } - else - { - NSLog(@"Error in conversion: return message is %@", response); - - //if (![GrowlApplicationBridge isGrowlRunning]) - { - [errorList addObject:response]; - [self updateErrorTable]; - } - } - } - } - } -} - -- (BOOL)isObjJFile:(NSString *)path -{ - return [[[path pathExtension] uppercaseString] isEqual:@"J"]; -} - -- (BOOL)isXIBFile:(NSString *)path -{ - path = [[path pathExtension] uppercaseString]; - return [path isEqual:@"XIB"] || [path isEqual:@"NIB"]; -} - -- (BOOL)prepareXCodeSupportProject -{ - XCodeSupportProjectName = [NSString stringWithFormat:@"%@.xcodeproj/", currentProjectName]; - XCodeTemplatePBXPath = [[NSBundle mainBundle] pathForResource:@"project" ofType:@"pbxproj"]; - XCodeSupportFolder = [NSURL URLWithString:@".xCodeSupport/" relativeToURL:currentProjectURL]; - XCodeSupportProject = [NSURL URLWithString:XCodeSupportProjectName relativeToURL:XCodeSupportFolder]; - XCodeSupportProjectSources = [NSURL URLWithString:@"Sources/" relativeToURL:XCodeSupportFolder]; - XCodeSupportPBXPath = [NSString stringWithFormat:@"%@/project.pbxproj", [XCodeSupportProject path]]; - - //[fm removeItemAtURL:XCodeSupportFolder error:nil]; - - // create the template project if it doesn't exist - if (![fm fileExistsAtPath:[XCodeSupportFolder path]]) - { - NSLog(@"Xcode support folder created at: %@", [XCodeSupportProject path]); - [fm createDirectoryAtPath:[XCodeSupportProject path] withIntermediateDirectories:YES attributes:nil error:nil]; - - NSLog(@"Copying project.pbxproj from %@ to %@", XCodeTemplatePBXPath, [XCodeSupportProject path]); - [fm copyItemAtPath:XCodeTemplatePBXPath toPath:XCodeSupportPBXPath error:nil]; - - NSLog(@"Reading the content of the project.pbxproj"); - NSMutableString *PBXContent = [NSMutableString stringWithContentsOfFile:XCodeSupportPBXPath encoding:NSUTF8StringEncoding error:nil]; - [PBXContent replaceOccurrencesOfString:@"${CappuccinoProjectName}" - withString:currentProjectName - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [PBXContent length])]; - [PBXContent replaceOccurrencesOfString:@"${CappuccinoProjectRelativePath}" - withString:@".." - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [PBXContent length])]; - - [PBXContent writeToFile:XCodeSupportPBXPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; - NSLog(@"PBX file adapted to the project"); - - NSLog(@"Creating source folder"); - [fm createDirectoryAtPath:[XCodeSupportProjectSources path] withIntermediateDirectories:YES attributes:nil error:nil]; - - - [NSThread detachNewThreadSelector:@selector(populateXCodeProject:)toTarget:self withObject:nil]; - return NO; - } - return YES; -} - -- (void)populateXCodeProject:(id)argement -{ - [GrowlApplicationBridge notifyWithTitle:[[currentProjectURL path] lastPathComponent] - description:@"Loading of project..." + [GrowlApplicationBridge notifyWithTitle:aTitle + description:aMessage notificationName:@"DefaultNotifications" iconData:nil priority:0 isSticky:NO clickContext:nil]; - - [self handleFileModification:[NSString stringWithFormat:@"%@", [currentProjectURL path]] ignoreDate:YES]; - NSArray *subdirs = [fm subpathsAtPath:[currentProjectURL path]]; - for (NSString *p in subdirs) - [self handleFileModification:[NSString stringWithFormat:@"%@/%@", [currentProjectURL path], p] ignoreDate:YES]; - - [labelStatus setStringValue:@"XCodeCapp is running"]; - [buttonOpenXCode setEnabled:YES]; - [buttonStop setEnabled:YES]; - [buttonStart setEnabled:NO]; - [spinner setHidden:YES]; - - [GrowlApplicationBridge notifyWithTitle:[[currentProjectURL path] lastPathComponent] - description:@"Your project has been loaded successfully!" - notificationName:@"DefaultNotifications" - iconData:nil - priority:0 - isSticky:NO - clickContext:nil]; - } -- (NSURL*)shadowURLForSourceURL:(NSURL*)aSourceURL -{ - NSMutableString *flattenedPath = [NSMutableString stringWithString:[aSourceURL path]]; - NSLog(@"Flattened path is : %@", flattenedPath); - [flattenedPath replaceOccurrencesOfString:@"/" - withString:@"_" - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [[aSourceURL path] length])]; - - NSString *basename = [NSString stringWithFormat:@"%@.h", [[flattenedPath stringByDeletingPathExtension] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; - - return [NSURL URLWithString:basename relativeToURL:XCodeSupportProjectSources]; -} - -- (void)computeIgnoredPaths -{ - NSString *ignorePath = [NSString stringWithFormat:@"%@/.xcodecapp-ignore", [currentProjectURL path]]; - - if (![fm fileExistsAtPath:ignorePath]) - return; - - NSString *ignoreFileContent = [NSString stringWithContentsOfFile:ignorePath encoding:NSUTF8StringEncoding error:nil]; - ignoredFilePaths = [NSMutableArray arrayWithArray:[ignoreFileContent componentsSeparatedByString:@"\n"]]; - - NSLog(@"ignored file paths are: %@", ignoredFilePaths); -} - -- (BOOL)isPathMatchingIgnoredPaths:(NSString*)aPath -{ - BOOL isMatching = NO; - - for (NSString *ignoredPath in ignoredFilePaths) - { - if ([ignoredPath isEqual:@""]) - continue; - - NSMutableString *regexp = [NSMutableString stringWithFormat:@"%@/%@", [currentProjectURL path], ignoredPath]; - [regexp replaceOccurrencesOfString:@"/" - withString:@"\\/" - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [regexp length])]; - - [regexp replaceOccurrencesOfString:@"." - withString:@"\\." - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [regexp length])]; - - [regexp replaceOccurrencesOfString:@"*" - withString:@".*" - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [regexp length])]; - - NSPredicate *regextest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regexp]; - if ([regextest evaluateWithObject:aPath]) - { - isMatching = YES; - - break; - } - } - - return isMatching; -} #pragma mark - #pragma mark Actions +/*! + Open the folder chooser and eventually start to listen + @param aSender the sender of the action + */ - (IBAction)chooseFolder:(id)aSender { NSOpenPanel *openPanel = [NSOpenPanel openPanel]; @@ -437,112 +182,96 @@ void fsevents_callback(ConstFSEventStreamRef streamRef, void *userData, size_t n if ([openPanel runModal] != NSFileHandlingPanelOKButton) return; - [spinner setHidden:NO]; - [spinner startAnimation:nil]; - - currentProjectURL = [[openPanel URLs] objectAtIndex:0]; - NSMutableString *tempName = [NSMutableString stringWithString:[[[openPanel URLs] objectAtIndex:0] lastPathComponent]]; - - [tempName replaceOccurrencesOfString:@" " - withString:@"_" - options:NSCaseInsensitiveSearch - range:NSMakeRange(0, [tempName length])]; - currentProjectName = [NSString stringWithString:tempName]; - - [self computeIgnoredPaths]; - [self initializeEventStreamWithPath:[currentProjectURL path]]; - - BOOL isProjectReady = [self prepareXCodeSupportProject]; - - [labelPath setStringValue:[currentProjectURL path]]; - [labelCurrentPath setHidden:NO]; - [buttonStart setEnabled:NO]; - - if (isProjectReady) - { - [spinner setHidden:YES]; - [buttonStop setEnabled:YES]; - [buttonOpenXCode setEnabled:YES]; - [labelStatus setStringValue:@"XCodeCapp is running"]; - } - - else - [labelStatus setStringValue:@"XCodeCapp is loading project..."]; - - [_statusItem setImage:_iconActive]; + [_xcc listenProjectAtPath:[NSString stringWithFormat:@"%@/", [[[openPanel URLs] objectAtIndex:0] path]]]; } +/*! + Stop listening to a project + @param aSender the sender of the action + */ - (IBAction)stopListener:(id)aSender { - currentProjectURL = nil; - currentProjectName = nil; - [ignoredFilePaths removeAllObjects]; - [labelPath setStringValue:@""]; - [labelCurrentPath setHidden:YES]; - [buttonOpenXCode setEnabled:NO]; - [buttonStop setEnabled:NO]; - [buttonStart setEnabled:YES]; - [labelStatus setStringValue:@"XCodeCapp is not running"]; - [self stopEventStream]; + [_xcc clear]; + [_statusItem setImage:_iconInactive]; + [menuItemProjectName setTitle:@"No project selected"]; + + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"LastOpenedPath"]; } +/*! + Open the xCode support project in xCode + @param aSender the sender of the action + */ - (IBAction)openXCode:(id)aSender { - if (!currentProjectURL) + if (![_xcc currentProjectURL]) return; - NSLog(@"Open Xcode project at URL : '%@'", [XCodeSupportProject path]); - system([[NSString stringWithFormat:@"open \"%@\"", [XCodeSupportProject path]] UTF8String]); + NSLog(@"Open Xcode project at URL : '%@'", [[_xcc XCodeSupportProject] path]); + system([[NSString stringWithFormat:@"open \"%@\"", [[_xcc XCodeSupportProject] path]] UTF8String]); } - +/*! + reload error table data and show it + @param aSender the sender of the action + */ - (void)updateErrorTable { [errorsTable reloadData]; [errorsPanel orderFront:self]; - NSLog(@"update?"); } +/*! + Clear all errors in errors table + @param aSender the sender of the action + */ - (IBAction)clearErrors:(id)sender { - [errorList removeAllObjects]; + [[_xcc errorList] removeAllObjects]; [errorsTable reloadData]; } + +/*! + Open the help file + @param aSender the sender of the action + */ +- (IBAction)openHelp:(id)aSender +{ + [helpTextView readRTFDFromFile:[[NSBundle mainBundle] pathForResource:@"help" ofType:@"rtfd"]]; + + [helpWindow center]; + [helpWindow makeKeyAndOrderFront:aSender]; +} + + #pragma mark - #pragma mark Delegates -- (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag -{ - [mainWindow makeKeyAndOrderFront:nil]; - - return YES; -} - - (BOOL)validateMenuItem:(NSMenuItem *)aMenuItem { if (aMenuItem == menuItemStart) - return !currentProjectURL; + return ![_xcc currentProjectURL]; if ((aMenuItem == menuItemStop) || (aMenuItem == menuItemOpenXCode)) - return !!currentProjectURL; + return !![_xcc currentProjectURL]; return YES; } - - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { - return [errorList count]; + return [[_xcc errorList] count]; } + - (id)tableView:(NSTableView*)aTableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { - return [errorList objectAtIndex:row]; + return [[_xcc errorList] objectAtIndex:row]; } - (void)tableViewColumnDidResize:(NSNotification *)tableView { [errorsTable noteHeightOfRowsWithIndexesChanged: - [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [errorList count])]]; + [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [[_xcc errorList] count])]]; } - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(int)aRow @@ -552,7 +281,7 @@ void fsevents_callback(ConstFSEventStreamRef streamRef, void *userData, size_t n float width = [tabCol width]; NSRect r = NSMakeRect(0,0,width,1000.0); NSCell *cell = [tabCol dataCellForRow:aRow]; - NSString *content = [errorList objectAtIndex:aRow]; + NSString *content = [[_xcc errorList] objectAtIndex:aRow]; [cell setObjectValue:content]; float height = [cell cellSizeForBounds:r].height; @@ -560,6 +289,6 @@ void fsevents_callback(ConstFSEventStreamRef streamRef, void *userData, size_t n height = 16.0; // Ensure miniumum height is 16.0 return height; - } + @end diff --git a/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/designable.nib b/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/designable.nib index 9181fede0..e9d1120b1 100644 --- a/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/designable.nib +++ b/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/designable.nib @@ -2,13 +2,13 @@ 0 - 11A511 - 1617 - 1138 - 566.00 + 11C74 + 1938 + 1138.23 + 567.00 com.apple.InterfaceBuilder.CocoaPlugin - 1617 + 1938 YES @@ -17,11 +17,11 @@ NSMenu NSTextFieldCell NSScrollView - NSButtonCell NSButton - NSProgressIndicator + NSButtonCell NSTableView NSCustomObject + NSTextView NSView NSWindowTemplate NSTextField @@ -32,11 +32,8 @@ com.apple.InterfaceBuilder.CocoaPlugin - YES - - YES - - + PluginDependencyRecalculationVersion + YES @@ -775,241 +772,13 @@ _NSMainMenu - - 3 - 2 - {{335, 180}, {331, 298}} - 1954021376 - xcodecapp-cocoa - NSWindow - - - {402, 378} - {402, 378} - - - 256 - - YES - - - 266 - {{7, 45}, {316, 12}} - - - - YES - - 68288064 - 138413056 - - - LucidaGrande - 9 - 16 - - - - 6 - System - controlColor - - 3 - MC42NjY2NjY2NjY3AA - - - - 6 - System - controlTextColor - - 3 - MAA - - - - - - - 266 - {{7, 65}, {316, 17}} - - - - YES - - 68288064 - 138413056 - Currently listening path: - - LucidaGrande-Bold - 13 - 16 - - - - - - - - - 266 - {{7, 108}, {316, 22}} - - - - YES - - 68288064 - 138413056 - XCodeCapp is not running - - LucidaGrande-Bold - 18 - 16 - - - - - 6 - System - alternateSelectedControlColor - - 1 - MCAwIDEAA - - - - - - - 293 - {{123, 17}, {86, 19}} - - - - YES - - -2080244224 - 134217728 - Stop - - LucidaGrande - 12 - 16 - - - -2038152961 - 164 - - - 400 - 75 - - - - - 293 - {{29, 17}, {86, 19}} - - - - YES - - -2080244224 - 134217728 - Start - - - -2038152961 - 164 - - - 400 - 75 - - - - - 293 - {{217, 17}, {85, 19}} - - - - YES - - -2080244224 - 134217728 - Xcode - - - -2038152961 - 164 - - - 400 - 75 - - - - - 269 - {{94, 147}, {142, 132}} - - - - YES - - -2080244224 - 134217728 - - - LucidaGrande - 13 - 1044 - - - -2041822977 - 98 - - NSImage - xcodecapp-cocoa - - - - 400 - 75 - - - - - 1293 - - {{126, 88}, {78, 12}} - - - - 16650 - 100 - - - {331, 298} - - - - - {{0, 0}, {1920, 1178}} - {402, 400} - {402, 400} - YES - AppController 8215 2 - {{196, 240}, {348, 62}} + {{196, 240}, {348, 140}} 611844096 About NSPanel @@ -1024,36 +793,62 @@ YES - 274 - {{17, -86}, {314, 128}} + 269 + {{17, 52}, {314, 36}} - YES 67239424 138674176 - XCodeCapp-cocoa is developed by Antoine Mercadal <primalmotion@archipelproject.org> + xCodeCapp-cocoa is developed by Antoine Mercadal <primalmotion@archipelproject.org> LucidaGrande 10 16 - + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + 3 MQA + + + 269 + {{95, 27}, {158, 11}} + + YES + + 68288064 + 138675200 + LABEL VERSION + + LucidaGrande-Bold + 11 + 3357 + + + + + + - {348, 62} + {348, 140} - - {{0, 0}, {1920, 1178}} + {{0, 0}, {1680, 1028}} {348, 81} {348, 81} YES @@ -1062,20 +857,37 @@ YES + + + YES + No project selected + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + - Start listenning - r - 1048576 + Start Listenning + 2147483647 - Stop listening - R - 1048576 + Stop Listening + 2147483647 @@ -1090,20 +902,10 @@ - - - Open Main window - o - 1048576 - 2147483647 - - - - Open Xcode - O - 1048576 + Open xCode + 2147483647 @@ -1144,11 +946,28 @@ + + + Help + + 2147483647 + + + + + + YES + YES + + + 2147483647 + + + Quit - q - 1048576 + 2147483647 @@ -1165,7 +984,7 @@ - + 256 YES @@ -1184,7 +1003,6 @@ 256 {512, 249} - YES @@ -1217,14 +1035,21 @@ 6 System headerTextColor - + + 3 + MAA + 337772032 0 Text Cell - + + LucidaGrande + 13 + 1044 + 6 @@ -1232,7 +1057,12 @@ controlBackgroundColor - + + 6 + System + controlTextColor + + 3 YES @@ -1260,7 +1090,6 @@ {{1, 1}, {512, 249}} - @@ -1271,7 +1100,6 @@ -2147483392 {{413, 17}, {15, 166}} - _doScroller: @@ -1282,7 +1110,6 @@ -2147483392 {{1, 183}, {427, 15}} - 1 @@ -1292,7 +1119,6 @@ {{-1, 35}, {514, 251}} - 133682 @@ -1305,13 +1131,16 @@ 289 {{407, 8}, {85, 19}} - YES -2080244224 134217728 Clear - + + LucidaGrande + 12 + 16 + -2038152961 164 @@ -1326,7 +1155,6 @@ 289 {{314, 8}, {85, 19}} - YES -2080244224 @@ -1344,11 +1172,192 @@ {512, 285} - - - {{0, 0}, {1920, 1178}} + {{0, 0}, {1680, 1028}} + {10000000000000, 10000000000000} + YES + + + 15 + 2 + {{163, 199}, {716, 571}} + 1685586944 + Help + NSWindow + + + + + 256 + + YES + + + 274 + + YES + + + 2304 + + YES + + + 2322 + {716, 14} + + + + + + + + + + + + YES + + + 134 + + + + 716 + 1 + + + 67121125 + 0 + + + + YES + + YES + NSBackgroundColor + NSColor + + + YES + + 6 + System + selectedTextBackgroundColor + + + + 6 + System + selectedTextColor + + + + + + + YES + + YES + NSColor + NSCursor + NSUnderline + + + YES + + 1 + MCAwIDEAA + + + {8, -8} + 13 + + + + + + + 1 + + 6 + {716, 10000000} + {238, 0} + + + + {{1, 1}, {716, 571}} + + + _NS:1478 + + + + {4, 5} + + 12582912 + + YES + + YES + + + + TU0AKgAAAHCAFUqgBVKsAAAAwdVQUqwaEQeIRGJRGFlYqwWLQ+JxuOQpVRmEx2RROKwOQyOUQSPyaUym +SxqWyKXyeYxyZzWbSuJTScRCbz2Nz+gRKhUOfTqeUai0OSxiWTiBQSHSGFquGwekxyAgAAAOAQAAAwAA +AAEAEAAAAQEAAwAAAAEAEAAAAQIAAwAAAAIACAAIAQMAAwAAAAEABQAAAQYAAwAAAAEAAQAAAREABAAA +AAEAAAAIARIAAwAAAAEAAQAAARUAAwAAAAEAAgAAARYAAwAAAAEAEAAAARcABAAAAAEAAABnARwAAwAA +AAEAAQAAAT0AAwAAAAEAAgAAAVIAAwAAAAEAAQAAAVMAAwAAAAIAAQABAAAAAA + + + + + + 3 + MCAwAA + + + + 4 + + + + 256 + {{702, 1}, {15, 571}} + + + _doScroller: + 1 + 0.85256409645080566 + + + + -2147483392 + {{-100, -100}, {87, 18}} + + + 1 + + _doScroller: + 1 + 0.94565218687057495 + + + {{-1, -1}, {718, 573}} + + + 133138 + + + + + + {716, 571} + + + + {{0, 0}, {1680, 1028}} {10000000000000, 10000000000000} YES @@ -1356,6 +1365,30 @@ YES + + + terminate: + + + + 458 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 401 + performMiniaturize: @@ -1396,14 +1429,6 @@ 127 - - - orderFrontStandardAboutPanel: - - - - 142 - performClose: @@ -1668,110 +1693,6 @@ 374 - - - delegate - - - - 401 - - - - labelPath - - - - 407 - - - - chooseFolder: - - - - 418 - - - - stopListener: - - - - 420 - - - - labelStatus - - - - 422 - - - - labelCurrentPath - - - - 423 - - - - makeKeyAndOrderFront: - - - - 433 - - - - openXCode: - - - - 437 - - - - buttonOpenXCode - - - - 438 - - - - buttonStart - - - - 439 - - - - buttonStop - - - - 440 - - - - spinner - - - - 444 - - - - mainWindow - - - - 445 - statusMenu @@ -1804,22 +1725,6 @@ 457 - - - terminate: - - - - 458 - - - - makeKeyAndOrderFront: - - - - 460 - menuItemStart @@ -1860,22 +1765,6 @@ 476 - - - dataSource - - - - 477 - - - - delegate - - - - 478 - clearErrors: @@ -1884,6 +1773,46 @@ 482 + + + helpWindow + + + + 507 + + + + helpTextView + + + + 515 + + + + openHelp: + + + + 517 + + + + menuItemProjectName + + + + 521 + + + + labelVersion + + + + 524 + orderFront: @@ -1908,13 +1837,31 @@ 498 + + + dataSource + + + + 477 + + + + delegate + + + + 478 + YES 0 - + + YES + @@ -2507,106 +2454,11 @@ - - 371 - - - YES - - - - - - 372 - - - YES - - - - - - - - - - - 376 - - 405 - - - YES - - - - - - 406 - - - - - 410 - - - YES - - - - - - 411 - - - - - 412 - - - YES - - - - - - 413 - - - - - 414 - - - YES - - - - - - 415 - - - - - 416 - - - YES - - - - - - 417 - - - 427 @@ -2622,6 +2474,7 @@ YES + @@ -2639,54 +2492,24 @@ - - 431 - - - YES - - - - - - 432 - - - - - 434 - - - YES - - - - - - 435 - - - - - 443 - - - 446 YES - - + + + + + @@ -2725,11 +2548,6 @@ - - 459 - - - 464 @@ -2832,6 +2650,84 @@ + + 505 + + + YES + + + + + + 506 + + + YES + + + + + + 511 + + + YES + + + + + + + + 512 + + + + + 513 + + + + + 514 + + + + + 516 + + + + + 518 + + + + + 519 + + + + + 520 + + + + + 522 + + + YES + + + + + + 523 + + + @@ -2905,24 +2801,7 @@ 350.IBPluginDependency 351.IBPluginDependency 354.IBPluginDependency - 371.IBNSWindowAutoPositionCentersHorizontal - 371.IBNSWindowAutoPositionCentersVertical - 371.IBPluginDependency - 371.IBWindowTemplateEditedContentRect - 371.NSWindowTemplate.visibleAtLaunch - 371.lastResizeAction - 372.IBPluginDependency 376.IBPluginDependency - 405.IBPluginDependency - 406.IBPluginDependency - 410.IBPluginDependency - 411.IBPluginDependency - 412.IBPluginDependency - 413.IBPluginDependency - 414.IBPluginDependency - 415.IBPluginDependency - 416.IBPluginDependency - 417.IBPluginDependency 427.IBNSWindowAutoPositionCentersHorizontal 427.IBNSWindowAutoPositionCentersVertical 427.IBPluginDependency @@ -2930,11 +2809,6 @@ 428.IBPluginDependency 429.IBPluginDependency 430.IBPluginDependency - 431.IBPluginDependency - 432.IBPluginDependency - 434.IBPluginDependency - 435.IBPluginDependency - 443.IBPluginDependency 446.IBPluginDependency 447.IBPluginDependency 448.IBPluginDependency @@ -2943,7 +2817,6 @@ 451.IBPluginDependency 452.IBPluginDependency 456.IBPluginDependency - 459.IBPluginDependency 464.IBPluginDependency 464.NSWindowTemplate.visibleAtLaunch 465.IBPluginDependency @@ -2960,6 +2833,19 @@ 494.IBPluginDependency 495.IBPluginDependency 5.IBPluginDependency + 505.IBPluginDependency + 505.NSWindowTemplate.visibleAtLaunch + 506.IBPluginDependency + 511.IBPluginDependency + 512.IBPluginDependency + 513.IBPluginDependency + 514.IBPluginDependency + 516.IBPluginDependency + 518.IBPluginDependency + 519.IBPluginDependency + 520.IBPluginDependency + 522.IBPluginDependency + 523.IBPluginDependency 56.IBPluginDependency 57.IBPluginDependency 58.IBPluginDependency @@ -3045,35 +2931,6 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - - - com.apple.InterfaceBuilder.CocoaPlugin - {{266, -670}, {351, 570}} - - - YES - - YES - IBResizeActionFinalFrame - IBResizeActionInitialFrame - - - YES - {{158, 405}, {351, 570}} - {{158, 515}, {531, 460}} - - - 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 @@ -3091,6 +2948,16 @@ 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 @@ -3124,9 +2991,6 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin - com.apple.InterfaceBuilder.CocoaPlugin @@ -3141,256 +3005,19 @@ - 498 - - - - YES - - AppController - NSObject - - YES - - YES - chooseFolder: - clearErrors: - openXCode: - stopListener: - - - YES - id - id - id - id - - - - YES - - YES - chooseFolder: - clearErrors: - openXCode: - stopListener: - - - YES - - chooseFolder: - id - - - clearErrors: - id - - - openXCode: - id - - - stopListener: - id - - - - - YES - - YES - buttonOpenXCode - buttonStart - buttonStop - errorsPanel - errorsTable - labelCurrentPath - labelPath - labelStatus - mainWindow - menuItemOpenXCode - menuItemStart - menuItemStop - spinner - statusMenu - - - YES - NSButton - NSButton - NSButton - NSPanel - NSTableView - NSTextField - NSTextField - NSTextField - NSWindow - NSMenuItem - NSMenuItem - NSMenuItem - NSProgressIndicator - NSMenu - - - - YES - - YES - buttonOpenXCode - buttonStart - buttonStop - errorsPanel - errorsTable - labelCurrentPath - labelPath - labelStatus - mainWindow - menuItemOpenXCode - menuItemStart - menuItemStop - spinner - statusMenu - - - YES - - buttonOpenXCode - NSButton - - - buttonStart - NSButton - - - buttonStop - NSButton - - - errorsPanel - NSPanel - - - errorsTable - NSTableView - - - labelCurrentPath - NSTextField - - - labelPath - NSTextField - - - labelStatus - NSTextField - - - mainWindow - NSWindow - - - menuItemOpenXCode - NSMenuItem - - - menuItemStart - NSMenuItem - - - menuItemStop - NSMenuItem - - - spinner - NSProgressIndicator - - - statusMenu - NSMenu - - - - - IBProjectSource - ./Classes/AppController.h - - - - NSDocument - - YES - - YES - printDocument: - revertDocumentToSaved: - runPageLayout: - saveDocument: - saveDocumentAs: - saveDocumentTo: - - - YES - id - id - id - id - id - id - - - - YES - - YES - printDocument: - revertDocumentToSaved: - runPageLayout: - saveDocument: - saveDocumentAs: - saveDocumentTo: - - - YES - - printDocument: - id - - - revertDocumentToSaved: - id - - - runPageLayout: - id - - - saveDocument: - id - - - saveDocumentAs: - id - - - saveDocumentTo: - id - - - - - IBProjectSource - ./Classes/NSDocument.h - - - + 524 + 0 IBCocoaFramework com.apple.InterfaceBuilder.CocoaPlugin.macosx + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 @@ -3403,13 +3030,11 @@ YES NSMenuCheckmark NSMenuMixedState - xcodecapp-cocoa YES {9, 8} {7, 2} - {512, 512} diff --git a/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/keyedobjects.nib b/Tools/xcodecapp-cocoa/English.lproj/MainMenu.nib/keyedobjects.nib index ea95968f5..d121ed2cf 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.h b/Tools/xcodecapp-cocoa/FSEventCallback.h new file mode 100644 index 000000000..cb7fd79a1 --- /dev/null +++ b/Tools/xcodecapp-cocoa/FSEventCallback.h @@ -0,0 +1,26 @@ +/* + * This file is a part of program xcodecapp-cocoa + * Copyright (C) 2011 Antoine Mercadal (primalmotion@archipelproject.org) + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#ifndef xcodecapp_cocoa_FSEventCallback_h +#define xcodecapp_cocoa_FSEventCallback_h + +#import "TNXCodeCapp.h" + +void fsevents_callback(ConstFSEventStreamRef, void*, size_t, void*, const FSEventStreamEventFlags*, const FSEventStreamEventId*); + +#endif diff --git a/Tools/xcodecapp-cocoa/FSEventCallback.m b/Tools/xcodecapp-cocoa/FSEventCallback.m new file mode 100644 index 000000000..aef270e3f --- /dev/null +++ b/Tools/xcodecapp-cocoa/FSEventCallback.m @@ -0,0 +1,57 @@ +/* + * This file is a part of program xcodecapp-cocoa + * Copyright (C) 2011 Antoine Mercadal (primalmotion@archipelproject.org) + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#import "FSEventCallback.h" + +/*! + This is the FSEvent callback + */ +void fsevents_callback(ConstFSEventStreamRef streamRef, + void *userData, + size_t numEvents, + void *eventPaths, + const FSEventStreamEventFlags eventFlags[], + const FSEventStreamEventId eventIds[]) +{ + TNXCodeCapp *xcc = (TNXCodeCapp *)userData; + size_t i; + + for(i = 0; i < numEvents; i++) + { + NSString *path = [(NSArray *)eventPaths objectAtIndex:i]; + + if (!(eventFlags[i] & 0x00010000) + || [xcc isPathMatchingIgnoredPaths:path] + || (![xcc isXIBFile:path] && ![xcc isObjJFile:path] && ![xcc isXCCIgnoreFile:path])) + continue; + + // 0x00000200 should be kFSEventStreamEventFlagItemRemoved but for some reason + // xCode mark this as not recognized. + if (eventFlags[i] & 0x00000200) + { + [xcc handleFileRemoval:path]; + } + + else + { + NSLog(@"this file has been modified or created"); + [xcc handleFileModification:path notify:YES]; + } + [xcc updateLastEventId:eventIds[i]]; + } +} \ No newline at end of file diff --git a/Tools/xcodecapp-cocoa/Info.plist b/Tools/xcodecapp-cocoa/Info.plist index ef8ec489f..36e05c47e 100644 --- a/Tools/xcodecapp-cocoa/Info.plist +++ b/Tools/xcodecapp-cocoa/Info.plist @@ -19,7 +19,7 @@ CFBundleSignature ???? CFBundleVersion - 1.0 + 2.0 NSMainNibFile MainMenu NSPrincipalClass diff --git a/Tools/xcodecapp-cocoa/TNXCodeCapp.h b/Tools/xcodecapp-cocoa/TNXCodeCapp.h new file mode 100644 index 000000000..74e584017 --- /dev/null +++ b/Tools/xcodecapp-cocoa/TNXCodeCapp.h @@ -0,0 +1,73 @@ +/* + * This file is a part of program xcodecapp-cocoa + * Copyright (C) 2011 Antoine Mercadal (primalmotion@archipelproject.org) + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#import +#import "PRHEmptyGrowlDelegate.h" +#import "FSEventCallback.h" + +extern NSString * const XCCDidPopulateProjectNotification; +extern NSString * const XCCConversionStartNotification; +extern NSString * const XCCConversionStopNotification; +extern NSString * const XCCListeningStartNotification; + + +@interface TNXCodeCapp : NSObject +{ + FSEventStreamRef stream; + NSFileManager *fm; + NSMutableArray *errorList; + NSMutableArray *ignoredFilePaths; + NSNumber *lastEventId; + NSString *currentProjectName; + NSString *parserPath; + NSString *XCodeSupportPBXPath; + NSString *XCodeSupportProjectName; + NSString *XCodeTemplatePBXPath; + NSString *profilePath; + NSURL *currentProjectURL; + NSURL *XCodeSupportFolder; + NSURL *XCodeSupportProject; + NSURL *XCodeSupportProjectSources; + PRHEmptyGrowlDelegate *growlDelegateRef; + NSObject *delegate; +} + +@property (retain) NSObject* delegate; +@property (retain) NSMutableArray* errorList; +@property (retain) NSURL* XCodeSupportProject; +@property (retain) NSURL* currentProjectURL; +@property (retain) NSString* currentProjectName; + +- (BOOL)isObjJFile:(NSString*)path; +- (void)computeIgnoredPaths; +- (BOOL)isPathMatchingIgnoredPaths:(NSString*)aPath; +- (BOOL)isXIBFile:(NSString *)path; +- (BOOL)isXCCIgnoreFile:(NSString *)path; +- (BOOL)prepareXCodeSupportProject; +- (NSURL*)shadowURLForSourceURL:(NSURL*)aSourceURL; +- (void)handleFileModification:(NSString*)fullPath notify:(BOOL)shouldNotify; +- (void)handleFileRemoval:(NSString*)fullPath; +- (void)initializeEventStreamWithPath:(NSString*)aPath; +- (void)stopEventStream; +- (void)updateLastEventId:(uint64_t)eventId; +- (void)listenProjectAtPath:(NSString *)path; +- (void)clear; +- (void)start; + + +@end diff --git a/Tools/xcodecapp-cocoa/TNXCodeCapp.m b/Tools/xcodecapp-cocoa/TNXCodeCapp.m new file mode 100644 index 000000000..bfd59d01a --- /dev/null +++ b/Tools/xcodecapp-cocoa/TNXCodeCapp.m @@ -0,0 +1,515 @@ +/* + * This file is a part of program xcodecapp-cocoa + * Copyright (C) 2011 Antoine Mercadal (primalmotion@archipelproject.org) + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * This program 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 this program. If not, see . + */ + +#import "TNXCodeCapp.h" + +NSString * const XCCDidPopulateProjectNotification = @"XCCDidPopulateProjectNotification"; +NSString * const XCCConversionStartNotification = @"XCCConversionStartNotification"; +NSString * const XCCConversionStopNotification = @"XCCConversionStopNotification"; +NSString * const XCCListeningStartNotification = @"XCCListeningStartNotification"; + + +@implementation TNXCodeCapp + +@synthesize delegate; +@synthesize errorList; +@synthesize XCodeSupportProject; +@synthesize currentProjectURL; +@synthesize currentProjectName; + +/*! + Initialize the AppController + */ +- (id)init +{ + self = [super init]; + + if (self) + { + errorList = [NSMutableArray arrayWithCapacity:10]; + fm = [NSFileManager defaultManager]; + ignoredFilePaths = [NSMutableArray new]; + parserPath = [[NSBundle mainBundle] pathForResource:@"parser" ofType:@"j"]; + lastEventId = [[NSUserDefaults standardUserDefaults] objectForKey:@"lastEventId"]; + + if([fm fileExistsAtPath:[@"~/.bash_profile" stringByExpandingTildeInPath]]) + profilePath = [@"source ~/.bash_profile" stringByExpandingTildeInPath]; + else if([fm fileExistsAtPath:[@"~/.profile" stringByExpandingTildeInPath]]) + profilePath = [@"source ~/.profile" stringByExpandingTildeInPath]; + else if([fm fileExistsAtPath:[@"~/.bashrc" stringByExpandingTildeInPath]]) + profilePath = [@"source ~/.bashrc" stringByExpandingTildeInPath]; + else if([fm fileExistsAtPath:[@"~/.zshrc" stringByExpandingTildeInPath]]) + profilePath = [@"source ~/.zshrc" stringByExpandingTildeInPath]; + else + { + NSAlert *alert = [NSAlert alertWithMessageText:@"Cannot find any valid profile file" + defaultButton:@"Ok" + alternateButton:nil + otherButton:nil + informativeTextWithFormat:@"We have checked for ~/.bash_profile, ~/.profile, ~/.bashrc and ~/.zshrc without luck.\n\nYou need to have on of this file to tell XCodeCapp-cocoa where is located nib2cib. Now we gonna try to without sourcing one this file and it may fail.\n\nIf you notice any error or weird behaviour, please look at Mac OS' Console.app for log message and open a ticket."]; + [alert runModal]; + profilePath = @""; + } + } + + return self; +} + +- (void)start +{ + NSString *lastOpenedPath = [[NSUserDefaults standardUserDefaults] objectForKey:@"LastOpenedPath"]; + if (lastOpenedPath) + { + if ([fm fileExistsAtPath:lastOpenedPath]) + { + NSString *message = [NSString stringWithFormat:@"Resuming project %@", [lastOpenedPath lastPathComponent], nil]; + + [delegate performSelector:@selector(growlWithTitle:message:) withObject:@"Resume project" withObject:message]; + [self listenProjectAtPath:[NSString stringWithFormat:@"%@/", lastOpenedPath]]; + } + else + { + [[NSUserDefaults standardUserDefaults] removeObjectForKey:@"LastOpenedPath"]; + } + } +} + +/*! + Initializes the FSEvent stream + @param aPath the path of the folder to listen + */ +- (void)initializeEventStreamWithPath:(NSString*)aPath +{ + NSArray *pathsToWatch = [NSArray arrayWithObject:aPath]; + void *appPointer = (void *)self; + FSEventStreamContext context = {0, appPointer, NULL, NULL, NULL}; + NSTimeInterval latency = 2.0; + + stream = FSEventStreamCreate(NULL, &fsevents_callback, &context, (CFArrayRef) pathsToWatch, + [lastEventId unsignedLongLongValue], (CFAbsoluteTime) latency, kFSEventStreamCreateFlagUseCFTypes | kFSEventStreamCreateFlagNoDefer | 0x00000010 ); + + FSEventStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode); + FSEventStreamStart(stream); +} + +/*! + Stop listening the FSEvent stream if active + */ +- (void)stopEventStream +{ + if (stream) + { + FSEventStreamStop(stream); + FSEventStreamInvalidate(stream); + stream = nil; + } +} + +/*! + Stops and clear the worker + */ +- (void)clear +{ + currentProjectURL = nil; + currentProjectName = nil; + [ignoredFilePaths removeAllObjects]; + [self stopEventStream]; +} + + +#pragma mark - +#pragma mark Utilities + +/*! + Update the last event ID. We use a method because + This is called from outside the class, in the FSEvent callback + @param eventId the current event ID value + */ +- (void)updateLastEventId:(uint64_t)eventId +{ + lastEventId = [NSNumber numberWithUnsignedLongLong:eventId]; + [[NSUserDefaults standardUserDefaults] setObject:lastEventId forKey:@"lastEventId"]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +/*! + Run a NSTask with the given arguments + @param arguments NSArray containing the NSTask arguments + @return NSarray containing the return code (int) and the eventual response (string) + */ +- (NSArray *)runTask:(NSArray *)arguments +{ + NSTask *task; + NSData *stdOut; + NSString *response; + NSNumber *status; + + task = [[NSTask alloc] init]; + + [task setLaunchPath: @"/bin/bash"]; + [task setArguments: arguments]; + [task setStandardOutput:[NSPipe pipe]]; + [task launch]; + [task waitUntilExit]; + + stdOut = [[[task standardOutput] fileHandleForReading] availableData]; + response = [[NSString alloc] initWithData:stdOut encoding:NSUTF8StringEncoding]; + status = [NSNumber numberWithInt:[task terminationStatus]]; + + return [NSArray arrayWithObjects:status, response, nil]; +} + +/*! + Handle a file modification. If it's a .J or XIB or NIB, it will + perform the according conversion. If it's .xcodecapp-ignore, it will + update the list of ignored files. + @param fullPath the full path of the modified file + @param shouldNotify if YES, Growl notifications will be displayed + */ +- (void)handleFileModification:(NSString*)fullPath notify:(BOOL)shouldNotify +{ + if ([self isPathMatchingIgnoredPaths:fullPath] || ![fm fileExistsAtPath:fullPath]) + return; + + NSLog(@"Starting to parse file modification %@", fullPath); + + NSArray *arguments; + NSString *successMsg; + NSNumber *status; + NSString *response; + NSString *errorTitle; + NSString *errorMsg; + NSString *splitedPath = [NSString stringWithFormat:@"%@/%@", [[fullPath pathComponents] objectAtIndex:[[fullPath pathComponents] count] - 2], [fullPath lastPathComponent]]; + NSString *shadowPath = [[self shadowURLForSourceURL:[NSURL URLWithString:[fullPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]] path]; + + NSLog(@"Shadow path is: %@", shadowPath); + + + if ([self isXIBFile:fullPath] || [self isObjJFile:fullPath] || [self isXCCIgnoreFile:fullPath]) + { + [[NSNotificationCenter defaultCenter] postNotificationName:XCCConversionStartNotification object:self]; + + if ([self isXIBFile:fullPath]) + { + NSLog(@"File is XIB file"); + arguments = [NSArray arrayWithObjects: @"-c", [NSString stringWithFormat:@"(%@; nib2cib '%@';) 2>&1", profilePath, fullPath],@"",nil]; + successMsg = @"The XIB file has been converted"; + } + else if ([self isObjJFile:fullPath]) + { + NSLog(@"File is J file"); + arguments = [NSArray arrayWithObjects: @"-c", [NSString stringWithFormat:@"(%@; objj '%@' '%@' '%@';) 2>&1", profilePath, parserPath, fullPath, shadowPath],@"",nil]; + successMsg = @"The Objective-J file has been converted"; + } + else if ([self isXCCIgnoreFile:fullPath]) + { + NSLog(@"File is .xcodecapp-ignore"); + [self computeIgnoredPaths]; + successMsg = @"Ignored files list updated"; + arguments = nil; + status = [NSNumber numberWithInt:0]; + } + + //Run the task and get the response if needed + if (arguments) + { + NSLog(@"Running task..."); + NSArray *statusInfo = [self runTask:arguments]; + + status = [statusInfo objectAtIndex:0]; + response = [statusInfo objectAtIndex:1]; + + NSLog(@"Task result is : %@", status); + NSLog(@"Task response is : %@", response); + } + + + if ([status intValue] == 0 && shouldNotify) + { + [delegate performSelector:@selector(growlWithTitle:message:) withObject:splitedPath withObject:successMsg]; + } + else if (![status intValue] == 0) + { + [errorList addObject:response]; + + errorTitle = [NSString stringWithFormat:@"ERROR: %@", splitedPath]; + errorMsg = [NSString stringWithFormat:@"Error was: %@.\n\n You may want to check in error list.", response]; + [delegate performSelector:@selector(growlWithTitle:message:) withObject:splitedPath withObject:errorMsg]; + } + + [[NSNotificationCenter defaultCenter] postNotificationName:XCCConversionStopNotification object:self]; + } + + NSLog(@"Computing done for file %@", fullPath); +} + +/*! + Handle a file deletion. If it's a .J, it will + remove the shadowed .h file. If it's .xcodecapp-ignore + it will reset the list of ignored files. + @param fullPath the full path of the modified file + @param shouldNotify if YES, Growl notifications will be displayed + */ +- (void)handleFileRemoval:(NSString*)fullPath +{ + if ([self isPathMatchingIgnoredPaths:fullPath] || [fm fileExistsAtPath:fullPath]) + return; + + if ([self isObjJFile:fullPath]) + { + NSString *shadowPath = [[self shadowURLForSourceURL:[NSURL URLWithString:[fullPath stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]] path]; + [fm removeItemAtPath:shadowPath error:nil]; + NSLog(@"Removing shadow file %@", shadowPath); + } + else if ([self isXCCIgnoreFile:fullPath]) + { + [self computeIgnoredPaths]; + } +} + +/*! + Check if given full path is Objective-J file + @param path the path to check + @return YES or NO + */ +- (BOOL)isObjJFile:(NSString *)path +{ + return [[[path pathExtension] uppercaseString] isEqual:@"J"]; +} + +/*! + Check if given full path is XIB or NIB file + @param path the path to check + @return YES or NO + */ +- (BOOL)isXIBFile:(NSString *)path +{ + path = [[path pathExtension] uppercaseString]; + return [path isEqual:@"XIB"] || [path isEqual:@"NIB"]; +} + +/*! + Check if given full path is the .xcodecapp-ignore file + @param path the path to check + @return YES or NO + */ +- (BOOL)isXCCIgnoreFile:(NSString *)path +{ + path = [path lastPathComponent]; + return [path isEqual:@".xcodecapp-ignore"]; +} + + +/*! + Check if .xCodeSupport needs to be initialized. + If not needed, check that all J files are mirrored. If no, + then launch conversion for missing mirrored h files + @return YES or NO + */ +- (BOOL)prepareXCodeSupportProject +{ + XCodeSupportProjectName = [NSString stringWithFormat:@"%@.xcodeproj/", currentProjectName]; + XCodeTemplatePBXPath = [[NSBundle mainBundle] pathForResource:@"project" ofType:@"pbxproj"]; + XCodeSupportFolder = [NSURL URLWithString:@".xCodeSupport/" relativeToURL:currentProjectURL]; + XCodeSupportProject = [NSURL URLWithString:XCodeSupportProjectName relativeToURL:XCodeSupportFolder]; + XCodeSupportProjectSources = [NSURL URLWithString:@"Sources/" relativeToURL:XCodeSupportFolder]; + XCodeSupportPBXPath = [NSString stringWithFormat:@"%@/project.pbxproj", [XCodeSupportProject path]]; + + //[fm removeItemAtURL:XCodeSupportFolder error:nil]; + + // create the template project if it doesn't exist + if (![fm fileExistsAtPath:[XCodeSupportFolder path]]) + { + NSLog(@"Xcode support folder created at: %@", [XCodeSupportProject path]); + [fm createDirectoryAtPath:[XCodeSupportProject path] withIntermediateDirectories:YES attributes:nil error:nil]; + + NSLog(@"Copying project.pbxproj from %@ to %@", XCodeTemplatePBXPath, [XCodeSupportProject path]); + [fm copyItemAtPath:XCodeTemplatePBXPath toPath:XCodeSupportPBXPath error:nil]; + + NSLog(@"Reading the content of the project.pbxproj"); + NSMutableString *PBXContent = [NSMutableString stringWithContentsOfFile:XCodeSupportPBXPath encoding:NSUTF8StringEncoding error:nil]; + [PBXContent replaceOccurrencesOfString:@"${CappuccinoProjectName}" + withString:currentProjectName + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [PBXContent length])]; + [PBXContent replaceOccurrencesOfString:@"${CappuccinoProjectRelativePath}" + withString:@".." + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [PBXContent length])]; + + [PBXContent writeToFile:XCodeSupportPBXPath atomically:YES encoding:NSUTF8StringEncoding error:nil]; + NSLog(@"PBX file adapted to the project"); + + NSLog(@"Creating source folder"); + [fm createDirectoryAtPath:[XCodeSupportProjectSources path] withIntermediateDirectories:YES attributes:nil error:nil]; + + + [NSThread detachNewThreadSelector:@selector(populateXCodeProject:)toTarget:self withObject:nil]; + return NO; + } + else + { + NSArray *subdirs = [fm subpathsAtPath:[currentProjectURL path]]; + for (NSString *p in subdirs) + { + NSString *path = [NSString stringWithFormat:@"%@/%@", [currentProjectURL path], p]; + NSString *shadow = [[self shadowURLForSourceURL:[NSURL URLWithString:path]] path]; + if ([self isObjJFile:path] && ![fm fileExistsAtPath:shadow] && ![[path lastPathComponent] isEqualToString:@"main.j"]) + { + NSLog(@"File %@ seems to be new. Computing it.", path); + [self handleFileModification:path notify:YES]; + } + } + return YES; + } +} + +/*! + Initialize the creation of the .xCodeSupport project. This + Operation is threaded + @param arguments Thread arguments (not used) + */ +- (void)populateXCodeProject:(id)arguments +{ + [delegate performSelector:@selector(growlWithTitle:message:) withObject:[[currentProjectURL path] lastPathComponent] withObject:@"Loading of project..."]; + + [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]; + + NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:currentProjectURL, @"URL", nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:XCCDidPopulateProjectNotification object:self userInfo:info]; +} + +/*! + Compute the mirorred (shadow) name for a given path + @param aSourceURL the origin path + @return NSURL representing the shadow path + */ +- (NSURL*)shadowURLForSourceURL:(NSURL*)aSourceURL +{ + NSMutableString *flattenedPath = [NSMutableString stringWithString:[aSourceURL path]]; + NSLog(@"Flattened path is : %@", flattenedPath); + [flattenedPath replaceOccurrencesOfString:@"/" + withString:@"_" + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [[aSourceURL path] length])]; + + NSString *basename = [NSString stringWithFormat:@"%@.h", [[flattenedPath stringByDeletingPathExtension] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; + + return [NSURL URLWithString:basename relativeToURL:XCodeSupportProjectSources]; +} + +/*! + Compute the ignored paths according to any existing + .xcodecapp-ignore file + */ +- (void)computeIgnoredPaths +{ + NSString *ignorePath = [NSString stringWithFormat:@"%@/.xcodecapp-ignore", [currentProjectURL path]]; + + if ([fm fileExistsAtPath:ignorePath]) + { + NSString *ignoreFileContent = [NSString stringWithContentsOfFile:ignorePath encoding:NSUTF8StringEncoding error:nil]; + ignoredFilePaths = [NSMutableArray arrayWithArray:[ignoreFileContent componentsSeparatedByString:@"\n"]]; + } + else + { + [ignoredFilePaths removeAllObjects]; + } + + [ignoredFilePaths addObject:@"*.git*"]; + [ignoredFilePaths addObject:@"*.svn*"]; + [ignoredFilePaths addObject:@"*Frameworks*"]; + [ignoredFilePaths addObject:@"*.xCodeSupport*"]; + + NSLog(@"ignored file paths are: %@", ignoredFilePaths); +} + +/*! + Check is given path should be ignored + @param aPath the path to check + @return YES if it should be ignored, NO otherwise + */ +- (BOOL)isPathMatchingIgnoredPaths:(NSString*)aPath +{ + BOOL isMatching = NO; + + for (NSString *ignoredPath in ignoredFilePaths) + { + if ([ignoredPath isEqual:@""]) + continue; + + NSMutableString *regexp = [NSMutableString stringWithFormat:@"%@/%@", [currentProjectURL path], ignoredPath]; + [regexp replaceOccurrencesOfString:@"/" + withString:@"\\/" + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [regexp length])]; + + [regexp replaceOccurrencesOfString:@"." + withString:@"\\." + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [regexp length])]; + + [regexp replaceOccurrencesOfString:@"*" + withString:@".*" + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [regexp length])]; + + NSPredicate *regextest = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regexp]; + if ([regextest evaluateWithObject:aPath]) + { + isMatching = YES; + + break; + } + } + + return isMatching; +} + +/*! + Start all needed processes for listening to a given path + @param path The folder path to listen to + */ +- (void)listenProjectAtPath:(NSString *)path +{ + NSMutableString *tempName = [NSMutableString stringWithString:[path lastPathComponent]]; + + currentProjectURL = [NSURL URLWithString:path]; + + [tempName replaceOccurrencesOfString:@" " + withString:@"_" + options:NSCaseInsensitiveSearch + range:NSMakeRange(0, [tempName length])]; + currentProjectName = [NSString stringWithString:tempName]; + + [self computeIgnoredPaths]; + + BOOL isProjectReady = [self prepareXCodeSupportProject]; + + [self initializeEventStreamWithPath:[currentProjectURL path]]; + + NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:path, @"path", [NSNumber numberWithInt:(isProjectReady) ? 1 : 0], @"ready", nil]; + [[NSNotificationCenter defaultCenter] postNotificationName:XCCListeningStartNotification object:self userInfo:info]; + + [[NSUserDefaults standardUserDefaults] setObject:[currentProjectURL path] forKey:@"LastOpenedPath"]; +} + +@end diff --git a/Tools/xcodecapp-cocoa/help.rtfd/1.PNG b/Tools/xcodecapp-cocoa/help.rtfd/1.PNG new file mode 100644 index 000000000..f5919a5d2 Binary files /dev/null and b/Tools/xcodecapp-cocoa/help.rtfd/1.PNG differ diff --git a/Tools/xcodecapp-cocoa/help.rtfd/2.PNG b/Tools/xcodecapp-cocoa/help.rtfd/2.PNG new file mode 100644 index 000000000..640fae1d4 Binary files /dev/null and b/Tools/xcodecapp-cocoa/help.rtfd/2.PNG differ diff --git a/Tools/xcodecapp-cocoa/help.rtfd/3.PNG b/Tools/xcodecapp-cocoa/help.rtfd/3.PNG new file mode 100644 index 000000000..88ae34c2f Binary files /dev/null and b/Tools/xcodecapp-cocoa/help.rtfd/3.PNG differ diff --git a/Tools/xcodecapp-cocoa/help.rtfd/TXT.rtf b/Tools/xcodecapp-cocoa/help.rtfd/TXT.rtf new file mode 100644 index 000000000..df5200b5e --- /dev/null +++ b/Tools/xcodecapp-cocoa/help.rtfd/TXT.rtf @@ -0,0 +1,137 @@ +{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf230 +{\fonttbl\f0\fnil\fcharset0 LucidaGrande;\f1\fswiss\fcharset0 Helvetica;\f2\fmodern\fcharset0 Courier; +} +{\colortbl;\red255\green255\blue255;} +\paperw11900\paperh16840\margl1440\margr1440\vieww19580\viewh15960\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural + +\f0\b\fs36 \cf0 xCodeCapp Help +\b0 \ +\ + +\b\fs24 What it xCodeCapp\ + +\b0\fs36 \ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj + +\fs24 \cf0 xCodeCapp-Cocoa is an utility tool that helps you to greatly improve your Cappuccino development workflow. One of the main stunning thing about Cappuccino is the ability to use Apple's xCode IDE to create your interfaces for web application. But Cappuccino can't read XIB (ones produced by xCode) directly and you have to run the tool nib2cib manually at each change of your interface. Moreover you cannot link Outlets and Actions directly.\ +Well, now all of this is possible, thanks to xCodeCapp-Cocoa. This tool is a port of another one written in Objective-J but much more faster and much more integrated. XCodeCapp-Cocoa will silently listen the directory tree of your Cappuccino project using Mac OS X FSEvent API \'97 no dirty polling \'97 and will convert your XIB files into CIB (ones that can be read by Cappuccino) at each change. It will also listen for your Objective-J files, and will convert them into hidden .h files in order to allow you to use Outlets and Actions from xCode as soon as you edit your code.\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\ + +\b Video +\b0 \ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj +\cf0 You can have a look on the video on this website to understand how it works: {\field{\*\fldinst{HYPERLINK "http://antoinemercadal.fr/xcodecappcocoa/"}}{\fldrslt http://antoinemercadal.fr/xcodecappcocoa/}}\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\ + +\b Quick start +\b0 \ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj +\cf0 xCodeCapp is very easy to use and require nearly no user interaction. First of all you need to launch it (which seems to be OK). It will display a menu bar icon at the top right of your screen. By clicking on the icon, you will see a menu:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc + +\f1 \cf0 {{\NeXTGraphic 1.PNG \width4700 \height4180 +}¬} +\f0 \ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj +\cf0 First, you need to choose your Cappuccino project. To do so, click on "Start Listening". A folder chooser will appear. Navigate to the root project folder.\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc + +\f1 \cf0 {{\NeXTGraphic 2.PNG \width12060 \height8360 +}¬}\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc + +\f0 \cf0 \ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ +\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qj +\cf0 You can choose either the folder itself, of you can enter the folder and select nothing. xCodeCapp will start to import your project. It will create a hidden folder in the root project directory named ".xCodeSupport". This folder contains mirrored files built by xCodeCapp. You should never go and modify anything into this folder. You should also ignore it if your project is in a SCM (git, subversion, etc.)\ +\ +Now, when you edit a Objective-J file and when you save, you will see a Growl notification indicating that the conversion is done. The same happens when you edit a XIB file, xCodeCapp will automatically use nib2cib to convert the XIB into a CIB.\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural +\cf0 \ +\ + +\b Play with XIBs\ +\ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qj + +\b0 \cf0 xCodeCapp mirrors your .j files into .h files in the .xCodeSupport folder. This allows to use Interface Builder to really link your outlets and actions with your code. When you create a new outlet in your Cappuccino classes and after saving, and so, after conversion by xCodeCapp, you will be able to see the outlet in interface builder. But to able to that, you need to launch the xCode support project.\ +To do so, click on the xCodeCapp icon, and select "Open xCode".\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc + +\f1 \cf0 {{\NeXTGraphic 3.PNG \width4600 \height4140 +}¬}\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural\qc + +\f0 \cf0 \ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj +\cf0 The xCode project will open. You can now play with interface builder.\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\ + +\b Ignoring files and folder\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj + +\b0 \cf0 xCodeCapp is able to ignore some files and/or folders. By default, it will ignore "Frameworks", ".git", ".svn", ".xCodeSupport" and "Build" directory. To add some path you can create a file in the root project directory (where is stored .xCodeSupport) named ".xcodecapp-ignore". The syntax is pretty straightforward:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ + +\f2 Build*\ +Libraries/Cappuccino*\ +Libraries/StropheCappuccino*\ +Libraries/*/Build/*\ +Categories*\ +.xCodeSupport*\ +Modules/* +\f0 \ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj +\cf0 You can use wildcard token "*" to say "everything". For example, " +\f2 Libraries/*/Build/* +\f0 " will ignore all files in "Build" folders located anywhere in "Libraries".\ +You must put only one ignore directive per line.\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\ + +\b Help\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj + +\b0 \cf0 This help message will only open at first launch. To consult it later, select "Open Help" in the xCodeCapp menu. You can also post any question to the Cappuccino mailing list ({\field{\*\fldinst{HYPERLINK "http://objectivej@googlegroups.com"}}{\fldrslt objectivej@googlegroups.com}}) or join us in our IRC channel ({\field{\*\fldinst{HYPERLINK "irc://irc.freenode.org/#cappuccino"}}{\fldrslt irc://irc.freenode.org/#cappuccino}}).\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural + +\b \cf0 Credits +\fs28 \ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qj + +\b0\fs24 \cf0 xCodeCapp was originally made by Francisco Tolmasky.\ +The Cocoa port is made by Antoine Mercadal.\ +This tool was built for the needs of Archipel Project and it's obviously open source and released under GPL v3.\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural +\cf0 \ +} \ No newline at end of file diff --git a/Tools/xcodecapp-cocoa/xcodecapp-cocoa-icon-active.psd b/Tools/xcodecapp-cocoa/xcodecapp-cocoa-icon-active.psd index 60e8aa273..47973705a 100644 Binary files a/Tools/xcodecapp-cocoa/xcodecapp-cocoa-icon-active.psd and b/Tools/xcodecapp-cocoa/xcodecapp-cocoa-icon-active.psd differ diff --git a/Tools/xcodecapp-cocoa/xcodecapp-cocoa-icon-working.png b/Tools/xcodecapp-cocoa/xcodecapp-cocoa-icon-working.png new file mode 100644 index 000000000..aeb981ca5 Binary files /dev/null and b/Tools/xcodecapp-cocoa/xcodecapp-cocoa-icon-working.png differ diff --git a/Tools/xcodecapp-cocoa/xcodecapp-cocoa.xcodeproj/project.pbxproj b/Tools/xcodecapp-cocoa/xcodecapp-cocoa.xcodeproj/project.pbxproj index 0efb2bf4d..d6205ae10 100644 --- a/Tools/xcodecapp-cocoa/xcodecapp-cocoa.xcodeproj/project.pbxproj +++ b/Tools/xcodecapp-cocoa/xcodecapp-cocoa.xcodeproj/project.pbxproj @@ -19,6 +19,10 @@ 027D999F13696A7000D3DB13 /* AppController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8E01A91E0DE9EED20008BB35 /* AppController.m */; }; 027D99A113696A7000D3DB13 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 027D99A213696A7000D3DB13 /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8E01A8DD0DE51A7C0008BB35 /* CoreServices.framework */; }; + 027FE49A1462C6CF00B1AB92 /* help.rtfd in Resources */ = {isa = PBXBuildFile; fileRef = 027FE4991462C6CF00B1AB92 /* help.rtfd */; }; + 027FE49D1462D74C00B1AB92 /* TNXCodeCapp.m in Sources */ = {isa = PBXBuildFile; fileRef = 027FE49C1462D74C00B1AB92 /* TNXCodeCapp.m */; }; + 027FE4BA1462F64E00B1AB92 /* xcodecapp-cocoa-icon-working.png in Resources */ = {isa = PBXBuildFile; fileRef = 027FE4B91462F64E00B1AB92 /* xcodecapp-cocoa-icon-working.png */; }; + 027FE4BD1462F7EB00B1AB92 /* FSEventCallback.m in Sources */ = {isa = PBXBuildFile; fileRef = 027FE4BC1462F7EB00B1AB92 /* FSEventCallback.m */; }; 02998CEB1369BF7D006C73DB /* Growl Registration Ticket.growlRegDict in Resources */ = {isa = PBXBuildFile; fileRef = 02998CEA1369BF7D006C73DB /* Growl Registration Ticket.growlRegDict */; }; 02998CF71369C339006C73DB /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 02998CF61369C339006C73DB /* Growl.framework */; }; 02998CF91369C38A006C73DB /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 02998CF61369C339006C73DB /* Growl.framework */; }; @@ -47,6 +51,12 @@ 026F3B6413866E7D00EE5B83 /* xcodecapp-cocoa-icon-active.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "xcodecapp-cocoa-icon-active.png"; sourceTree = ""; }; 027D9989136969DD00D3DB13 /* xcodecapp-cocoa.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "xcodecapp-cocoa.pch"; sourceTree = ""; }; 027D99A613696A7000D3DB13 /* xcodecapp-cocoa.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "xcodecapp-cocoa.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 027FE4991462C6CF00B1AB92 /* help.rtfd */ = {isa = PBXFileReference; lastKnownFileType = wrapper.rtfd; path = help.rtfd; sourceTree = ""; }; + 027FE49B1462D74C00B1AB92 /* TNXCodeCapp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TNXCodeCapp.h; sourceTree = ""; }; + 027FE49C1462D74C00B1AB92 /* TNXCodeCapp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TNXCodeCapp.m; sourceTree = ""; }; + 027FE4B91462F64E00B1AB92 /* xcodecapp-cocoa-icon-working.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "xcodecapp-cocoa-icon-working.png"; sourceTree = ""; }; + 027FE4BB1462F7D600B1AB92 /* FSEventCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSEventCallback.h; sourceTree = ""; }; + 027FE4BC1462F7EB00B1AB92 /* FSEventCallback.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSEventCallback.m; sourceTree = ""; }; 02998CEA1369BF7D006C73DB /* Growl Registration Ticket.growlRegDict */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = "Growl Registration Ticket.growlRegDict"; sourceTree = ""; }; 02998CF61369C339006C73DB /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Growl.framework; sourceTree = ""; }; 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -85,6 +95,10 @@ 651DAE1D13B0CAB900ECA3F0 /* PRHEmptyGrowlDelegate.m */, 8E01A91D0DE9EED20008BB35 /* AppController.h */, 8E01A91E0DE9EED20008BB35 /* AppController.m */, + 027FE49B1462D74C00B1AB92 /* TNXCodeCapp.h */, + 027FE49C1462D74C00B1AB92 /* TNXCodeCapp.m */, + 027FE4BB1462F7D600B1AB92 /* FSEventCallback.h */, + 027FE4BC1462F7EB00B1AB92 /* FSEventCallback.m */, ); name = Classes; sourceTree = ""; @@ -140,6 +154,8 @@ 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( + 027FE4B91462F64E00B1AB92 /* xcodecapp-cocoa-icon-working.png */, + 027FE4991462C6CF00B1AB92 /* help.rtfd */, 026F3B6413866E7D00EE5B83 /* xcodecapp-cocoa-icon-active.png */, 026F3B6113866B0B00EE5B83 /* xcodecapp-cocoa-icon-inactive.png */, 024A041113699D6800DCBE4D /* parser.j */, @@ -221,6 +237,8 @@ 02998CEB1369BF7D006C73DB /* Growl Registration Ticket.growlRegDict in Resources */, 026F3B6213866B0B00EE5B83 /* xcodecapp-cocoa-icon-inactive.png in Resources */, 026F3B6513866E7D00EE5B83 /* xcodecapp-cocoa-icon-active.png in Resources */, + 027FE49A1462C6CF00B1AB92 /* help.rtfd in Resources */, + 027FE4BA1462F64E00B1AB92 /* xcodecapp-cocoa-icon-working.png in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -234,6 +252,8 @@ 027D999E13696A7000D3DB13 /* main.m in Sources */, 027D999F13696A7000D3DB13 /* AppController.m in Sources */, 651DAE1F13B0CAB900ECA3F0 /* PRHEmptyGrowlDelegate.m in Sources */, + 027FE49D1462D74C00B1AB92 /* TNXCodeCapp.m in Sources */, + 027FE4BD1462F7EB00B1AB92 /* FSEventCallback.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; };