// // DNDAppDelegate.m // Do Not Disturb // // Created by Chris Karr on 7/19/07. // Copyright 2007 __MyCompanyName__. All rights reserved. // #import "DNDAppDelegate.h" #import "ObserverManager.h" #import "Observer.h" #import "NaiveBayesLearner.h" #import "DNDDefines.h" @implementation DNDAppDelegate - (DNDAppDelegate *) init { if (self = [super init]) { sensors = [ObserverManager observers]; trainingTimer = nil; timer = nil; logger = [[LearnerLogger alloc] init]; NaiveBayesLearner * l = [[NaiveBayesLearner alloc] init]; [logger setLearner:l]; } return self; } - (void) activateStatusMenu { NSStatusBar *bar = [NSStatusBar systemStatusBar]; theItem = [bar statusItemWithLength:NSVariableStatusItemLength]; [theItem retain]; [theItem setTitle:nil]; [theItem setImage:[NSImage imageNamed:@"bell-small"]]; [theItem setAlternateImage:[NSImage imageNamed:@"bell-small-alt"]]; [theItem setHighlightMode:YES]; [theItem setMenu:menu]; available = YES; } - (void) awakeFromNib { [self activateStatusMenu]; [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(handleUpdate:) name:DND_UPDATE object:nil]; [eventsWindow setTitle:@"Do Not Disturb - Collecting Information"]; [eventsWindow setBackgroundColor:[NSColor colorWithCalibratedWhite:0.8 alpha:1.0]]; NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; float interval = [defaults floatForKey:@"Sensor Interval"]; if (interval == 0.0) { interval = 30.0; [defaults setFloat:interval forKey:@"Sensor Interval"]; } [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"Sensor Interval" options:NSKeyValueObservingOptionNew context:NULL]; [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"Training Interval" options:NSKeyValueObservingOptionNew context:NULL]; [[NSUserDefaults standardUserDefaults] addObserver:self forKeyPath:@"Contexts" options:NSKeyValueObservingOptionNew context:NULL]; timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(scanAgain:) userInfo:nil repeats:YES]; progressTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateProgress:) userInfo:nil repeats:YES]; [updateProgress setMaxValue:(double) interval]; [updateProgress setMinValue:0.0]; [updateProgress setDoubleValue:0.0]; [updateProgress setUsesThreadedAnimation:YES]; [self scan:self]; } - (void) observeValueForKeyPath: (NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; if ([keyPath isEqual:@"Sensor Interval"]) { float interval = [defaults floatForKey:@"Sensor Interval"]; if (interval > 0.0) { [timer invalidate]; [progressTimer invalidate]; timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(scanAgain:) userInfo:nil repeats:YES]; progressTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateProgress:) userInfo:nil repeats:YES]; [updateProgress setMaxValue:(double) interval]; [updateProgress setDoubleValue:0.0]; } } else if ([keyPath isEqual:@"Training Interval"]) { float interval = [defaults floatForKey:@"Training Interval"]; if (interval > 0.0 && trainingTimer != nil) { [trainingTimer invalidate]; trainingTimer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(trainAgain:) userInfo:nil repeats:YES]; [trainingTimer retain]; } } else if ([keyPath isEqual:@"Contexts"]) { } } - (void) scanAgain:(NSTimer *) t { [self scan:t]; [updateProgress setDoubleValue:0.0]; } - (void) updateProgress:(NSTimer *) t { [updateProgress incrementBy:1.0]; } - (IBAction) about:(id) sender { [NSApp orderFrontStandardAboutPanel:sender]; } - (IBAction) preferences:(id) sender { if ([preferencesWindow isVisible]) [preferencesWindow orderOut:sender]; else { [NSApp activateIgnoringOtherApps:YES]; [preferencesWindow makeKeyAndOrderFront:sender]; } } - (IBAction) quit:(id) sender { [NSApp terminate:sender]; } - (IBAction) scan:(id) sender { Observer * sensor; NSEnumerator * iter = [sensors objectEnumerator]; while ((sensor = (Observer *) [iter nextObject])) { if ([sensor isEnabled]) [sensor scan]; } } - (IBAction) toggleScan:(id) sender { if (timer == nil) { NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; float interval = [defaults floatForKey:@"Sensor Interval"]; if (interval == 0.0) interval = 60.0; timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(scanAgain:) userInfo:nil repeats:YES]; progressTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateProgress:) userInfo:nil repeats:YES]; [updateProgress setUsesThreadedAnimation:YES]; [updateProgress setMaxValue:(double) interval]; [updateProgress setMinValue:0.0]; [updateProgress setDoubleValue:0.0]; [pause setTitle:@"Pause"]; [eventsWindow setTitle:@"Do Not Disturb - Collecting Information"]; } else { [timer invalidate]; timer = nil; [pause setTitle:@"Resume"]; [eventsWindow setTitle:@"Do Not Disturb - Paused"]; } } - (IBAction) toggleEventLog:(id) sender { if ([eventsWindow isVisible]) [eventsWindow orderOut:sender]; else { [NSApp activateIgnoringOtherApps:YES]; [eventsWindow makeKeyAndOrderFront:sender]; } } - (IBAction) togglePredictedStatus:(id) sender { if ([predictionWindow isVisible]) [predictionWindow orderOut:sender]; else { [NSApp activateIgnoringOtherApps:YES]; [predictionWindow makeKeyAndOrderFront:sender]; } } - (IBAction) clear:(id) sender { [eventsController setFilterPredicate:nil]; [eventsController removeObjects:[eventsController arrangedObjects]]; } - (NSString *) getTrainingStatus { if (trainingTimer == nil) return @"Not Training"; else return @"Training"; } - (NSNumber *) getExampleCount { return [logger readingCount]; } - (NSSet *) getSensors { return sensors; } - (void) setSensors:(NSSet *) sensors { } - (IBAction) toggleTraining:(id) sender { [self willChangeValueForKey:@"trainingStatus"]; if (trainingTimer == nil) { NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; float interval = [defaults floatForKey:@"Training Interval"]; if (interval == 0.0) interval = 60.0; trainingTimer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(trainAgain:) userInfo:nil repeats:YES]; [trainingTimer retain]; [trainingButton setTitle:@"Stop"]; [trainingItem setTitle:@"Stop Training..."]; NSRunInformationalAlertPanel (@"Training started", @"Training has been started. The learner will periodically prompted you for the current context. ", @"OK", nil, nil); } else { [trainingTimer invalidate]; trainingTimer = nil; [trainingButton setTitle:@"Start"]; [trainingItem setTitle:@"Start Training..."]; NSRunInformationalAlertPanel (@"Training Stopped", @"Training has been stopped.", @"OK", nil, nil); } [self didChangeValueForKey:@"trainingStatus"]; } - (void) trainAgain:(NSTimer *) t { [self scan:self]; if ([[NSUserDefaults standardUserDefaults] boolForKey:@"Prompt Sound"]) [[NSSound soundNamed:@"bell"] play]; [theItem setImage:[NSImage imageNamed:@"bell-small-color"]]; [NSApp activateIgnoringOtherApps:YES]; [trainingWindow makeKeyAndOrderFront:self]; } - (IBAction) setStatus:(id) sender { [self trainAgain:nil]; } - (IBAction) setTrainingContext:(id) sender { [self willChangeValueForKey:@"predictedStatus"]; [self willChangeValueForKey:@"exampleCount"]; [theItem setImage:[NSImage imageNamed:@"bell-small"]]; [trainingWindow orderOut:self]; NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; float interval = [defaults floatForKey:@"Sensor Interval"]; if (interval == 0.0) interval = 60.0; NSString * label = [statePulldown stringValue]; [defaults setValue:label forKey:@"Last Context"]; NSMutableArray * contexts = [NSMutableArray arrayWithArray:[defaults valueForKey:@"Contexts"]]; if (![contexts containsObject:label]) { [contexts addObject:label]; [contexts sortUsingSelector:@selector(compare:)]; [defaults setValue:contexts forKey:@"Contexts"]; } NSMutableArray * readings = [NSMutableArray array]; NSArray * events = [eventsController arrangedObjects]; NSEnumerator * iter = [events objectEnumerator]; NSDictionary * event; NSDate * now = [NSDate date]; while (event = [iter nextObject]) { NSDate * date = [event valueForKey:@"date"]; if ([now timeIntervalSinceDate:date] <= interval) [readings addObject:event]; } [logger logLabel:label readings:readings]; [self didChangeValueForKey:@"exampleCount"]; [self didChangeValueForKey:@"predictedStatus"]; [privacyManager captureScreen:sender]; } - (NSString *) getPredictedStatus { float interval = [[NSUserDefaults standardUserDefaults] floatForKey:@"Sensor Interval"]; if (interval == 0.0) interval = 60.0; NSArray * events = [eventsController arrangedObjects]; NSMutableArray * activeEvents = [NSMutableArray array]; NSEnumerator * iter = [events objectEnumerator]; NSDictionary * event; NSDate * now = [NSDate date]; while (event = [iter nextObject]) { NSDate * date = [event valueForKey:@"date"]; if ([now timeIntervalSinceDate:date] <= interval) [activeEvents addObject:event]; } Learner * l = [logger getLearner]; return [l getLabelForExample:activeEvents]; } - (void) handleUpdate:(NSNotification *) msg { [self willChangeValueForKey:@"predictedStatus"]; [eventsController addObject:[msg userInfo]]; [self didChangeValueForKey:@"predictedStatus"]; [[NSDistributedNotificationCenter defaultCenter] postNotificationName:DND_PREDICTION_UPDATE object:nil userInfo:nil]; } - (IBAction) clearLog:(id) sender { [self willChangeValueForKey:@"exampleCount"]; [logger clear]; [self didChangeValueForKey:@"exampleCount"]; } @end