This is BongAppController.m in view mode; [Download] [Up]
#import "BongAppController.h"
#import "dpsclient/dpsNeXT.h"
#import <sys/time.h>
#import <misckit/misckit.h> // Get stuff for string class...
@implementation BongAppController
- setBongSound:sender
{
const char *types[] = { "snd", NULL };
OpenPanel *openPanel = [OpenPanel new]; // Convenience reference. Reduce code, and maybe calls.
MiscString *pathString = [MiscString newWithString:""]; // Grab an empty instance of MiscString... ;')
if ( pathString ) {
if ( [[openPanel allowMultipleFiles:NO] runModalForTypes:types] ) {
[pathString catStrings:[openPanel directory], "/", *[openPanel filenames], NULL]; // Construct full path.
[pathString replaceHomeWithTilde]; // Attempt to substitute a tilde for home path.
[soundTextField setStringValue:[pathString stringValueAndFree]]; // Get the value, and free object.
[self textWillEnd:soundTextField]; // Get the sound to be updated.
NXWriteDefault("BongApp", [defaultsStringTable valueForStringKey:"bongFileSoundPath"], [soundTextField stringValue]);
}
} else NXLogError("%s Error -- setBongSound: could not aquire a new MiscString instance.\n",
[[self class] name]);
return ( self );
}
- setWhenToPlay:sender
{
MiscString *whenToPlay = [MiscString newWithString:""];
MiscString *indexString = [[MiscString alloc] init];
int index;
for ( index = 1; index <= 4; index++ ) {
if ( [[sender findCellWithTag:index] intValue] ) {
[indexString sprintf:"%d", index];
[whenToPlay cat:[defaultsStringTable valueForStringKey:[indexString stringValue]]];
[whenToPlay cat:" "];
}
}
[whenToPlay squashSpaces];
NXWriteDefault("BongApp", [defaultsStringTable valueForStringKey:"whenToPlay"] ,[whenToPlay stringValueAndFree]);
return ( self );
}
// Timed Entry functions.
void updateTimeAndCheck(DPSTimedEntry teNum, double now, id self)
{
[self updateTimeAndCheck];
}
// Application Delegate Methods
// Set up the timed entry to check for the time (hour or half hour).
- appDidInit:sender
{
int defaultIndex;
MiscString *index = [[MiscString alloc] init];
MiscString *whenToPlayDefaults = [[MiscString alloc] init];
MiscString *currPlayDefault = [[MiscString alloc] init];
[soundTextField setStringValue:NXReadDefault("BongApp", [defaultsStringTable valueForStringKey:"bongFileSoundPath"])];
[self textWillEnd:soundTextField]; // "force" retrieval of the sound
if (!(DPSAddTimedEntry(1.0, (DPSTimedEntryProc)&updateTimeAndCheck, self, NX_BASETHRESHOLD))) {
NXLogError("%s Error -- appDidInit: could not aquire"
" timed entry for time check.\n",
[[self class] name]);
[NXApp terminate:self];
}
// Get whenToPlay default, and set the appropriate switches to reflect the settings.
// Assuming that the switch defaults are labeled 1 - 4 (or even higher if there are more switches
// that you add. I kept it simple since most people don't want "bong'in" going on more than
// at the quarter hour marks.
[whenToPlayDefaults setString:NXReadDefault("BongApp", [defaultsStringTable valueForStringKey:"whenToPlay"])];
for ( defaultIndex = 4; defaultIndex; defaultIndex-- ) {
[index sprintf:"%d", defaultIndex];
[currPlayDefault setString:[defaultsStringTable valueForStringKey:[index stringValue]]];
[[whenToPlayMatrix findCellWithTag:defaultIndex] setIntValue:
([whenToPlayDefaults spotOfRegex:[currPlayDefault stringValue]] != -1 ) ? YES : NO];
}
return ( self );
}
- showInfoPanel:sender;
{
MiscString *revisionString = [[MiscString alloc] init];
MiscString *infoNibPath = [[MiscString alloc] init];
char buffer[MAXPATHLEN + 1];
if ( !infoPanel ) {
[[NXBundle mainBundle] getPath:buffer forResource:"Info" ofType:"nib"];
[infoNibPath setString:buffer];
if ( ![NXApp loadNibFile:[infoNibPath stringValue] owner:self withNames:NO fromZone:[self zone]] ) {
NXLogError("%s Error -- showInfoPanel: could not load the info panel.\n",
[[self class] name]);
return ( self );
} else {
[revisionString sprintf:"Ver %.2f Rel %.2f", B_VERSION, B_RELEASE];
[revisionTextField setStringValue:[revisionString stringValue]];
}
}
[infoPanel makeKeyAndOrderFront:self];
return ( self );
}
- updateTimeAndCheck
{
struct tm *localTime;
struct timeval currentTime;
Sound *totalBongSound;
// Get the time in seconds, and microseconds from 1970 ...
gettimeofday (¤tTime, NULL);
// ... and then break it down into something useful. The time that is.
localTime = localtime (&(currentTime.tv_sec));
// Update the fields
[[timeForm findCellWithTag:HOURS] setIntValue:localTime->tm_hour];
[[timeForm findCellWithTag:MINUTES] setIntValue:localTime->tm_min];
[[timeForm findCellWithTag:SECONDS] setIntValue:localTime->tm_sec];
// Now based on the values, do a bong for hour, or half hour...
if ( localTime->tm_sec == 0 ) {
// If we are on a 15 minute interval, then check if we are allowed to play...
if ((localTime->tm_min == 0) && ([self _allowedToPlayAt:B_ON_THE_HOUR])) {
bongCount = localTime->tm_hour;
if ( bongCount == 0 ) bongCount = 12;
else if ( bongCount > 12 ) bongCount -= 12;
} else if ((localTime->tm_min == 15) && ([self _allowedToPlayAt:B_QUARTER_AFTER])) {
bongCount = 1;
} else if ((localTime->tm_min == 30) && ([self _allowedToPlayAt:B_HALF_AFTER])) {
bongCount = 1;
} else if ((localTime->tm_min == 45) && ([self _allowedToPlayAt:B_QUARTER_TILL])) {
bongCount = 1;
} else return ( self ); // ... else return.
// Get a new sound, then construct many bongs and play the sound
totalBongSound = [[Sound alloc] init];
while ( bongCount-- ) {
[totalBongSound insertSamples:[Sound findSoundFor:"bongSound"] at:[totalBongSound dataSize]];
if ( [totalBongSound needsCompacting] ) [totalBongSound compactSamples]; // Compact if sound has fragmentation.
}
[totalBongSound play]; // Spawn a sound playing thread, and play the sound.
}
return ( self );
}
// Another support method
- (BOOL)_allowedToPlayAt:(int)timeRequested
{
MiscString *defaultTimes = [[MiscString alloc] init];
MiscString *indexString = [[MiscString alloc] init];
// Check and see if we are within our known limits of play, and then get the defaults if so.
if ((timeRequested < B_ON_THE_HOUR) || (timeRequested > B_QUARTER_TILL)) return ( NO );
[defaultTimes setString:NXReadDefault("BongApp", [defaultsStringTable valueForStringKey:"whenToPlay"])];
// Now use the MiscString instance methods to find any instance of a known string in the defaults.
[indexString sprintf:"%d", timeRequested];
if ( [defaultTimes rspotOfRegex:[defaultsStringTable valueForStringKey:[indexString stringValue]]] < 0 ) return ( NO );
return ( YES );
}
// Text field delegate overrides...
- (BOOL)textWillEnd:sender
{
Sound *newSound;
Sound *oldSound;
MiscString *pathString = [MiscString newWithString:[soundTextField stringValue]];
oldSound = [Sound removeSoundForName:"bongSound"];
[pathString replaceTildeWithHome];
if (!(newSound = [Sound addName:"bongSound" fromSoundfile:[pathString stringValue]])) {
NXLogError("%s Error -- textWillEnd: could not aquire the new sound (%s).\n",
[[self class] name], [pathString stringValue]);
if ( oldSound ) [Sound addName:"bongSound" sound:oldSound];
return ( NO );
}
NXWriteDefault("BongApp", [defaultsStringTable valueForStringKey:"bongFileSoundPath"], [soundTextField stringValue]);
return ( YES ); // Allow the changes.
}
// Going to add some simple/smashing animation to the information panel.
- smashClock:sender
{
return ( self );
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.