Sunday, April 18, 2010

Folder watcher on Mac

I have written this sample code for keeping watch for files inside the folder.

If you add files or delete files from the folder. The files will be listed out with details.

The contents of file are getting saved into database. This example will also demonstrate use of core data.

#import

@interface FolderWatcher_AppDelegate : NSObject
{
NSWindow *window;

NSPersistentStoreCoordinator *persistentStoreCoordinator;
NSManagedObjectModel *managedObjectModel;
NSManagedObjectContext *managedObjectContext;

NSArray *manageDataArr;

IBOutlet NSTextField *folderpathTextField;
IBOutlet NSTableView *tableView;
NSString *folderPath;
NSArray *contents;
NSMutableArray *dataArray;
NSTimer *timer;


}

@property (nonatomic, retain) IBOutlet NSWindow *window;

@property (nonatomic, retain, readonly) NSPersistentStoreCoordinator *persistentStoreCoordinator;
@property (nonatomic, retain, readonly) NSManagedObjectModel *managedObjectModel;
@property (nonatomic, retain, readonly) NSManagedObjectContext *managedObjectContext;

- (IBAction)saveAction:sender;
-(IBAction)showStoredVal:(id)sender;
-(IBAction)removeStoredVal:(id)sender;


-(void)folderTracker;
-(IBAction)start:(id)sender;

@end
//
// FolderWatcher_AppDelegate.m
// FolderWatcher
//
// Created by Ashish on 07/03/10.
// Copyright Ashish Kumar Pandita 2010 . All rights reserved.
//

#import "FolderWatcher_AppDelegate.h"
#import "TableAttributes.h"

@implementation FolderWatcher_AppDelegate

@synthesize window;
-(id)init
{
if(self = [super init])
{
folderPath = [folderpathTextField stringValue];
contents = nil;
dataArray=[[NSMutableArray alloc]init];

}
return self;
}
/**
Implementation of dealloc, to release the retained variables.
*/

- (void)dealloc {

[window release];
[managedObjectContext release];
[persistentStoreCoordinator release];
[managedObjectModel release];

[super dealloc];
}


/**
Returns the support directory for the application, used to store the Core Data
store file. This code uses a directory named "FolderWatcher" for
the content, either in the NSApplicationSupportDirectory location or (if the
former cannot be found), the system's temporary directory.
*/

- (NSString *)applicationSupportDirectory {

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : NSTemporaryDirectory();
return [basePath stringByAppendingPathComponent:@"FolderWatcher"];
}


/**
Creates, retains, and returns the managed object model for the application
by merging all of the models found in the application bundle.
*/

- (NSManagedObjectModel *)managedObjectModel {

if (managedObjectModel) return managedObjectModel;

managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
return managedObjectModel;
}


/**
Returns the persistent store coordinator for the application. This
implementation will create and return a coordinator, having added the
store for the application to it. (The directory for the store is created,
if necessary.)
*/

- (NSPersistentStoreCoordinator *) persistentStoreCoordinator {

if (persistentStoreCoordinator) return persistentStoreCoordinator;

NSManagedObjectModel *mom = [self managedObjectModel];
if (!mom) {
NSAssert(NO, @"Managed object model is nil");
NSLog(@"%@:%s No model to generate a store from", [self class], _cmd);
return nil;
}

NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *applicationSupportDirectory = [self applicationSupportDirectory];
NSError *error = nil;

if ( ![fileManager fileExistsAtPath:applicationSupportDirectory isDirectory:NULL] ) {
if (![fileManager createDirectoryAtPath:applicationSupportDirectory withIntermediateDirectories:NO attributes:nil error:&error]) {
NSAssert(NO, ([NSString stringWithFormat:@"Failed to create App Support directory %@ : %@", applicationSupportDirectory,error]));
NSLog(@"Error creating application support directory at %@ : %@",applicationSupportDirectory,error);
return nil;
}
}

NSURL *url = [NSURL fileURLWithPath: [applicationSupportDirectory stringByAppendingPathComponent: @"storedata.sqlite"]];
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: mom];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:url
options:nil
error:&error]){
[[NSApplication sharedApplication] presentError:error];
[persistentStoreCoordinator release], persistentStoreCoordinator = nil;
return nil;
}

return persistentStoreCoordinator;
}

/**
Returns the managed object context for the application (which is already
bound to the persistent store coordinator for the application.)
*/

- (NSManagedObjectContext *) managedObjectContext {

if (managedObjectContext) return managedObjectContext;

NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [[NSManagedObjectContext alloc] init];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}

/**
Returns the NSUndoManager for the application. In this case, the manager
returned is that of the managed object context for the application.
*/

- (NSUndoManager *)windowWillReturnUndoManager:(NSWindow *)window {
return [[self managedObjectContext] undoManager];
}


/**
Performs the save action for the application, which is to send the save:
message to the application's managed object context. Any encountered errors
are presented to the user.
*/

- (IBAction) saveAction:(id)sender {

NSError *error = nil;
//NSManagedObject *filedetails = [filedetails valueForKey:@"name"];

if (![[self managedObjectContext] commitEditing]) {
NSLog(@"%@:%s unable to commit editing before saving", [self class], _cmd);
}


if (![[self managedObjectContext] save:&error]) {
[[NSApplication sharedApplication] presentError:error];
}
}


/**
Implementation of the applicationShouldTerminate: method, used here to
handle the saving of changes in the application managed object context
before the application terminates.
*/

- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender {

if (!managedObjectContext) return NSTerminateNow;

if (![managedObjectContext commitEditing]) {
NSLog(@"%@:%s unable to commit editing to terminate", [self class], _cmd);
return NSTerminateCancel;
}

if (![managedObjectContext hasChanges]) return NSTerminateNow;

NSError *error = nil;
if (![managedObjectContext save:&error]) {

// This error handling simply presents error information in a panel with an
// "Ok" button, which does not include any attempt at error recovery (meaning,
// attempting to fix the error.) As a result, this implementation will
// present the information to the user and then follow up with a panel asking
// if the user wishes to "Quit Anyway", without saving the changes.

// Typically, this process should be altered to include application-specific
// recovery steps.

BOOL result = [sender presentError:error];
if (result) return NSTerminateCancel;

NSString *question = NSLocalizedString(@"Could not save changes while quitting. Quit anyway?", @"Quit without saves error question message");
NSString *info = NSLocalizedString(@"Quitting now will lose any changes you have made since the last successful save", @"Quit without saves error question info");
NSString *quitButton = NSLocalizedString(@"Quit anyway", @"Quit anyway button title");
NSString *cancelButton = NSLocalizedString(@"Cancel", @"Cancel button title");
NSAlert *alert = [[NSAlert alloc] init];
[alert setMessageText:question];
[alert setInformativeText:info];
[alert addButtonWithTitle:quitButton];
[alert addButtonWithTitle:cancelButton];

NSInteger answer = [alert runModal];
[alert release];
alert = nil;

if (answer == NSAlertAlternateReturn) return NSTerminateCancel;

}

return NSTerminateNow;
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{

NSLog(@"DIDFINISH LAUNCHING");

}



-(IBAction)start:(id)sender
{
if([sender state]==0)
{
[sender setTitle:@"STOP"];
folderPath = [[folderpathTextField stringValue] copy];
NSLog(@"[folderpathTextField stringValue] : %@",[folderpathTextField stringValue]);
NSLog(@"folder path : %@",folderPath);
[self folderTracker];

}else {
[sender setTitle:@"START"];
[timer invalidate];
}


}

-(void)folderTracker
{
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkFolderStatus) userInfo:nil repeats:YES];


}

-(void)checkFolderStatus
{
NSLog(@"Tracker");
contents =[[NSFileManager defaultManager] directoryContentsAtPath:folderPath];

[self performSelectorOnMainThread:@selector(getFileProperties) withObject:contents waitUntilDone:YES];


}

-(void)getFileProperties

{
NSLog(@"contents %@", contents);
NSMutableArray *size = [[NSMutableArray alloc]init]; ///////allocating the arrays for holding the values for size type and icon////////////
NSMutableArray *type = [[NSMutableArray alloc]init];
NSMutableArray *icon1 = [[NSMutableArray alloc]init];
[dataArray removeAllObjects];
for(int i = 0; i<[contents count]; i++)
{
NSString *finalPath = [folderPath stringByAppendingPathComponent:[contents objectAtIndex:i]];
NSDictionary *fileAttributes1 = [[NSFileManager defaultManager] fileAttributesAtPath: finalPath traverseLink:NO];
NSLog(@"i = %d; fileAttributes1 %@",i,fileAttributes1);

NSImage * icon = [[NSWorkspace sharedWorkspace] iconForFile: finalPath]; //////////retriving the icon for the particular file ///////////

[icon1 addObject:icon]; //////////adding the icon object to the array of icons///////////
if(fileAttributes1 !=nil)
{
NSNumber *filsiz; /////////////defining the the filsize, fileType///////////////////////
NSNumber *kb=[NSNumber numberWithInt:1024];
NSString *size1;
if(filsiz=[fileAttributes1 objectForKey:NSFileSize])
{

if([filsiz intValue]>[kb intValue])
{
int siz=[filsiz intValue];
int num=(siz/1024);
size1=[NSString stringWithFormat:@"%d KB",num];
if(num>1024)
{
int num1=(num/(1024));
size1=[NSString stringWithFormat:@"%d MB",num1];
[size addObject:size1];

}

[size addObject:size1];
}
/////////////adding the filsiz to the size attribute defined in the tableAttributes class//////////
else
{
int siz=[filsiz intValue];
size1=[NSString stringWithFormat:@"%d Bytes",siz];
[size addObject:size1];
}
}
NSString * kind = [[NSWorkspace sharedWorkspace] typeOfFile:finalPath error:nil];
NSLog(@"file-----%@",kind);
NSString *folder=[NSString stringWithFormat:@"public.folder"];
if(kind==folder)
{
NSString *folderName=[NSString stringWithFormat:@"Folder"];
[type addObject:folderName];
}
else
{
NSString *fileKind= [[NSWorkspace sharedWorkspace] preferredFilenameExtensionForType:kind];
if(fileKind !=nil)
{
NSLog(@"file is %@",fileKind);
[type addObject:fileKind];
}
else{
fileKind=[NSString stringWithFormat:@"null"];
[type addObject:kind];
}
}
}


TableAttributes *tableAttributes = [[TableAttributes alloc]init];
tableAttributes.name = [contents objectAtIndex:i];
tableAttributes.fileSizeInfo= [size objectAtIndex:i];
tableAttributes.type= [type objectAtIndex:i];
tableAttributes.icon= [icon1 objectAtIndex:i];
if([[NSFileManager defaultManager]isReadableFileAtPath:finalPath])
{
//NSFileHandle *fileHandle = [[NSFileHandle alloc]init];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:finalPath];
NSData *data = [fileHandle availableData];
NSLog(@"%@", data);

tableAttributes.fileContents = data;

}
if([tableAttributes.name isEqualToString:@".DS_Store"])
{
//
}
else{
[dataArray addObject:tableAttributes];

}
[tableAttributes release];
}
[size release];
[icon1 release];
[type release];
[tableView reloadData];

//the data base should be updated again and again beacoz if file in the foder is not deleted but only its contents are changed, new contents should be also updated in db.

NSManagedObjectContext * context = [self managedObjectContext];
NSFetchRequest * fetch = [[[NSFetchRequest alloc] init] autorelease];
[fetch setEntity:[NSEntityDescription entityForName:@"fileDetails" inManagedObjectContext:context]];
NSArray * result = [context executeFetchRequest:fetch error:nil];
for (id basket in result)
[context deleteObject:basket];
NSError *saveError;
if (![[self managedObjectContext] save:&saveError]) {
[NSException raise:@"SaveException" format:@"Error while saving", ([saveError description] != nil) ? [saveError description] : @"Unknown Error"];
}


//storing the data

for (int i=0; i<[dataArray count]; i++) {
NSManagedObjectContext *context = [self managedObjectContext];
NSManagedObject *newobj = [NSEntityDescription insertNewObjectForEntityForName:@"fileDetails" inManagedObjectContext:context];

int fileSizeInfo = [[[dataArray objectAtIndex:i]fileSizeInfo]intValue];

[newobj setValue:[[dataArray objectAtIndex:i]name] forKey:@"name"];
[newobj setValue:[NSNumber numberWithInt:fileSizeInfo] forKey:@"size"];
[newobj setValue:[[dataArray objectAtIndex:i]fileContents] forKey:@"content"];
NSError *saveError;
if (![[self managedObjectContext] save:&saveError]) {
[NSException raise:@"SaveException" format:@"Error while saving", ([saveError description] != nil) ? [saveError description] : @"Unknown Error"];
}


}



}

-(IBAction)showStoredVal:(id)sender
{

NSFetchRequest *dataFetch = [[[NSFetchRequest alloc] init] autorelease];
[dataFetch setEntity:[NSEntityDescription entityForName:@"fileDetails" inManagedObjectContext:managedObjectContext]];
NSSortDescriptor* sortOrdering = [[[NSSortDescriptor alloc] initWithKey:@"name" ascending:YES] autorelease];
[dataFetch setSortDescriptors:[NSArray arrayWithObject:sortOrdering]];

NSError *fetchError;
manageDataArr = [managedObjectContext executeFetchRequest:dataFetch error:&fetchError];
for(int i = 0;i<[manageDataArr count]; i++)
{
NSLog(@"name::, %@", [[manageDataArr objectAtIndex:i] valueForKey:@"name"]);
NSLog(@"size::, %@", [[manageDataArr objectAtIndex:i] valueForKey:@"size"]);
NSLog(@"content::, %@", [[manageDataArr objectAtIndex:i] valueForKey:@"content"]);
}


}
-(IBAction)removeStoredVal:(id)sender{

NSManagedObjectContext * context = [self managedObjectContext];
NSFetchRequest * fetch = [[[NSFetchRequest alloc] init] autorelease];
[fetch setEntity:[NSEntityDescription entityForName:@"fileDetails" inManagedObjectContext:context]];
NSArray * result = [context executeFetchRequest:fetch error:nil];
for (id basket in result)
[context deleteObject:basket];
NSError *saveError;
if (![[self managedObjectContext] save:&saveError]) {
[NSException raise:@"SaveException" format:@"Error while saving", ([saveError description] != nil) ? [saveError description] : @"Unknown Error"];
}


}


///////////////////////////////table view delegate method///////////////////////////////////////////////////
#pragma mark -

-(id)tableView:(NSTableView *)aTableView
objectValueForTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
NSString *identifier = [aTableColumn identifier];
TableAttributes *obj = [dataArray objectAtIndex:rowIndex];
return [obj valueForKey:identifier];
}


-(int)numberOfRowsInTableView:(NSTableView *)aTableView
{
return [dataArray count];
}

-(void)tableView:(NSTableView *)aTableView
setObjectValue:(id)anObject
forTableColumn:(NSTableColumn *)aTableColumn
row:(int)rowIndex
{
NSString *identifier = [aTableColumn identifier];
TableAttributes *obj = [dataArray objectAtIndex:rowIndex];
[obj setValue:anObject forKey:identifier];
}



Download the source from here: source code