Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
psWindow.m
/* |
File: psWindow.m |
Abstract: Pull in data from the UI and from the source folders to pass back to |
the psController. |
Version: 1.0 |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple |
Computer, Inc. ("Apple") in consideration of your agreement to the |
following terms, and your use, installation, modification or |
redistribution of this Apple software constitutes acceptance of these |
terms. If you do not agree with these terms, please do not use, |
install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and |
subject to these terms, Apple grants you a personal, non-exclusive |
license, under Apple's copyrights in this original Apple software (the |
"Apple Software"), to use, reproduce, modify and redistribute the Apple |
Software, with or without modifications, in source and/or binary forms; |
provided that if you redistribute the Apple Software in its entirety and |
without modifications, you must retain this notice and the following |
text and disclaimers in all such redistributions of the Apple Software. |
Neither the name, trademarks, service marks or logos of Apple Computer, |
Inc. may be used to endorse or promote products derived from the Apple |
Software without specific prior written permission from Apple. Except |
as expressly stated in this notice, no other rights or licenses, express |
or implied, are granted by Apple herein, including but not limited to |
any patent rights that may be infringed by your derivative works or by |
other works in which the Apple Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE |
MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION |
THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS |
FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND |
OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL |
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, |
MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED |
AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), |
STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE |
POSSIBILITY OF SUCH DAMAGE. |
Copyright © 2005 Apple Computer, Inc., All Rights Reserved |
*/ #import "psWindow.h" |
@implementation psWindow |
//-------------------------------- application delegate------------------------------ |
/* applicationWillBecomeActive |
aNotification (unused) |
Whenever the application becomes active, refresh the iPhotoData so that it is always up to date. |
*/ |
- (void)applicationWillBecomeActive:(NSNotification *)aNotification{ |
[self refreshIPhotoData: NULL]; |
} |
/* awakeFromNib |
When we first open the nib with a psWindow, let's set up some default values... |
*/ |
-(void)awakeFromNib |
{ |
/* if we have a transition selection button, store off which index has the random |
transition selection...*/ |
if (gTransitionSelectionField != nil) |
gIndexOfRandom = [gTransitionSelectionField indexOfItemWithTitle:@"(random)"]; |
//update the iphoto album data |
[self refreshIPhotoData: NULL]; |
} |
//----------------------------- update internal variables ------------------------------- |
/* getMasterImageDict |
albumData = CFDictionaryRef from an iPhoto Album plist |
get the dictionary in the iPhoto CFDictionary (albumData) which |
has each image's metadata (including fileurl) stored by key. |
*/ |
-(NSDictionary *)getMasterImageDict:(CFDictionaryRef)albumData{ |
if (albumData == nil) |
return nil; |
return ((NSDictionary *)CFDictionaryGetValue(albumData, @"Master Image List")); |
} |
/* getItemKeysForAlbum |
albumData = CFDictionaryRef from an iPhoto Album plist |
atIndex = the index of the specific album we're interested in |
returns the array of keys indicating which photos are in this album |
*/ |
-(NSArray *)getItemKeysForAlbum:(CFDictionaryRef)albumData atIndex:(int)index{ |
if (albumData == nil) |
return nil; |
if (gAlbumsArray==nil) |
return nil; |
//count how many albums we have |
CFIndex numAlbums = CFArrayGetCount((CFArrayRef)gAlbumsArray); |
if (numAlbums < 1){ |
return nil; |
} |
//for indexed album dict, go get the array of item keys |
CFDictionaryRef curAlbumDict = CFArrayGetValueAtIndex ( (CFArrayRef)gAlbumsArray, index); |
CFArrayRef itemKeys = nil; |
if (!CFDictionaryGetValueIfPresent(curAlbumDict, @"KeyList", (const void**)&itemKeys)){ |
return nil; |
} |
return ([(NSArray*)itemKeys retain]); |
} |
/* collectAlbumNames |
albumData = CFDictionaryRef from an iPhoto Album plist |
returns the array of album names |
*/ |
-(NSArray *)collectAlbumNames:(CFDictionaryRef) albumData{ |
if (albumData == nil) |
return nil; |
//get the list of albums |
if (!CFDictionaryGetValueIfPresent(albumData, @"List of Albums", (const void **)&gAlbumsArray)) |
return nil; |
else [gAlbumsArray retain]; |
//count how many albums we have |
CFIndex i = 0, numAlbums = CFArrayGetCount((CFArrayRef)gAlbumsArray); |
if (numAlbums < 1){ |
return nil; |
} |
//make a mutable array to return |
CFMutableArrayRef albumNamesArray = CFArrayCreateMutable(kCFAllocatorDefault, numAlbums, NULL); |
if (albumNamesArray == nil){ |
return nil; |
} |
//for each album dict, go get the name and store it in the return array |
for (i = 0; i< numAlbums; i++){ |
CFDictionaryRef curAlbumDict = CFArrayGetValueAtIndex ( (CFArrayRef)gAlbumsArray, i); |
CFStringRef curAlbumName = nil; |
if (!CFDictionaryGetValueIfPresent(curAlbumDict, @"AlbumName", (const void**)&curAlbumName)){ |
return nil; |
} |
CFArraySetValueAtIndex ( albumNamesArray, i, [(NSString *)curAlbumName retain]); |
} |
return ((NSArray*)albumNamesArray); |
} |
/* initIPhotoData |
find the iPhoto Library album data |
read out the album names to update the UI |
update the UI appropriately |
also update the cached gMasterImageDictList |
*/ |
-(void)initIPhotoData{ |
// first clear out all the globals that we might be holding on to |
// since we can get called to init multiple times and the world |
// might have changed out from underneath us. |
if (gPlist!=nil) |
gPlist = nil; |
if (gMasterImageDictList!=nil) |
[gMasterImageDictList release]; |
if (gAlbumsArray!=nil)[gAlbumsArray release]; |
if (gKeysForAlbum!=nil)[gKeysForAlbum release]; |
gSelectedAlbumIndex = 0; |
//make a path to the iphoto library ("~/Pictures/iPhoto Library/AlbumData.xml") |
NSString *albumDataPath = [[[NSHomeDirectory() |
stringByAppendingPathComponent:@"Pictures"] |
stringByAppendingPathComponent:@"iPhoto Library"] |
stringByAppendingPathComponent:@"AlbumData.xml"]; |
//if there is an iPhoto Library |
NSFileManager *manager = [NSFileManager defaultManager]; |
if ([manager fileExistsAtPath:albumDataPath]){ |
NSData *plistData; |
NSString *error; |
NSPropertyListFormat format; |
//suck in all the data from the iPhoto Library's album plist |
plistData = [NSData dataWithContentsOfFile:albumDataPath]; |
gPlist = [NSPropertyListSerialization propertyListFromData:plistData |
mutabilityOption:NSPropertyListImmutable |
format:&format |
errorDescription:&error]; |
if(!gPlist) |
{ |
NSLog(error); |
[error release]; |
} else { |
//pull out the album names and update the UI with them |
NSArray *albumNames = [self collectAlbumNames:(CFDictionaryRef)gPlist]; |
[self setAlbumNames:albumNames]; |
//update our cached globals |
gMasterImageDictList = [[self getMasterImageDict:(CFDictionaryRef)gPlist] retain]; |
//update the default sequence name with the UI selected value. |
[self setSelectedAlbum:NULL]; |
} |
} |
} |
//-------------------------------- update UI --------------------------------- |
/* setAlbumNames |
albumNames = array iPhoto album names |
update the album selection popup in the UI with those in albumNames |
*/ |
-(void)setAlbumNames:(NSArray*)albumNames{ |
//store off which item is selected |
NSString* selectedTitle = nil; |
if ([gAlbumPopup numberOfItems] > 1) |
selectedTitle = [gAlbumPopup titleOfSelectedItem]; |
//then rebuild the list |
[gAlbumPopup removeAllItems]; |
[gAlbumPopup addItemsWithTitles:albumNames]; |
//then restore the selection if it is there |
if (selectedTitle != nil){ |
int selectedIndex = [gAlbumPopup indexOfItemWithTitle:selectedTitle]; |
if (selectedIndex < 0) |
selectedIndex = 0; |
[gAlbumPopup selectItemAtIndex:selectedIndex]; |
} |
} |
/* refreshIPhotoData |
sender (unused) |
refresh the iPhotoData so that it is up to date |
*/ |
- (IBAction)refreshIPhotoData:(id)sender{ |
[self initIPhotoData]; |
} |
/* setSelectedAlbum |
sender (unused) |
stores off the array of photo keys from the dictionary and |
updates the UI default output name to match the selected album name |
*/ |
- (IBAction)setSelectedAlbum:(id)sender{ |
gSelectedAlbumIndex = [gAlbumPopup indexOfSelectedItem]; |
if (gSelectedAlbumIndex != -1){ |
//cache off the keys for this album |
gKeysForAlbum = [self getItemKeysForAlbum:(CFDictionaryRef)gPlist atIndex:gSelectedAlbumIndex]; |
//update UI |
[gSlideshowTitleField setStringValue:[gAlbumPopup titleOfSelectedItem]]; |
} |
} |
//-------------------------------- timebase functions --------------------------------- |
/* getFPS |
go check out the framerate popup and return an int value for the XML to use. This |
includes converting 29.97 to 30. NOTE: We will aslo return NTSCRate as "TRUE" for |
this case. |
*/ |
-(int)getFPS{ |
NSString *curFramerate =[gFramerateSelectionField titleOfSelectedItem]; |
if (NSOrderedSame == [curFramerate compare:@"29.97"]){ |
return 30; |
} else return [curFramerate intValue]; |
} |
/* getTimebase |
convert getFPS output to a string |
*/ |
-(NSString*)getTimebase{ |
return[[NSNumber numberWithInt:[self getFPS]] stringValue]; |
} |
/* getNTSCRate |
convert getFPS output to what the NTSCRate should be. |
note... if you actually want 30FPS in addition to 29.97 you'll |
need to add a little more smarts to this so you can put both |
30, non-ntsc and 30, ntsc rate into the XML. |
*/ |
-(NSString*)getNTSCRate{ |
if ([self getFPS]==30){ |
return @"TRUE"; |
} |
return @"FALSE"; |
} |
/* getSeqPreset |
convert getFPS output to what default sequence preset to use. |
*/ |
-(NSString*)getSeqPreset{ |
if ([self getFPS]==30){ |
return @"DV NTSC 48 kHz"; |
} else return @"DV PAL 48 kHz"; |
} |
//-------------------------------- durations functions --------------------------------- |
/* getClipDuration |
convert the UI clip duration in seconds to some number |
of frames. Note that for 29.97 we will slowly drift out of |
sync with timecode since we're using 30 for this calculation. |
*/ |
-(int)getClipDuration{ |
return ([gClipDurationField intValue]*[self getFPS]); |
} |
/* getTransitionDuration |
convert the UI clip duration in seconds to some number |
of frames. Note that for 29.97 we will slowly drift out of |
sync with timecode since we're using 30 for this calculation. |
*/ |
-(int)getTransitionDuration{ |
return ([gTransitionDurationField intValue] *[self getFPS]); |
} |
/* getMediaDuration |
convert the UI clip duration in seconds to some number |
of frames. We want to setup the media duration to be long |
enough to cover the transitions on both before and after this clip |
*/ |
-(NSString*)getMediaDuration{ |
int value = [self getClipDuration]+(4*[self getTransitionDuration]); |
return [[NSNumber numberWithInt:value] stringValue]; |
} |
/* getMediaIn |
pOut = the corresponding media out time to the returned media in time. |
note that the media in time is offset from 0 to leave room for the transition |
to extend into. |
*/ |
-(NSString*)getMediaIn:(int*)pOut{ |
int value = [self getTransitionDuration]; |
if (pOut != nil) |
*pOut = value+[self getClipDuration]+2*[self getTransitionDuration]; |
return [[NSNumber numberWithInt:value] stringValue]; |
} |
/* getTransitionDuration |
pIntValue = the corresponding transition duration in int format for |
use in calculations of start, and end as well as total media |
convert the UI transition duration in seconds to some number |
of frames. Note that for 29.97 we will slowly drift out of |
sync with timecode since we're using 30 for this calculation. |
*/ |
-(NSString*)getTransitionDuration: (int*)pIntValue{ |
int intValue = 0; |
intValue = ([self getTransitionDuration]); |
if (pIntValue != nil) |
*pIntValue = intValue; |
return [[NSNumber numberWithInt:intValue] stringValue]; |
} |
//-------------------------------- output settings functions --------------------------------- |
/* shouldCreateNewProject |
returns the state of UI checkbox |
*/ |
-(BOOL)shouldCreateNewProject{ |
if (gCreateNewProjectButton != nil) |
if ([gCreateNewProjectButton state] == NSOnState) |
return TRUE; |
else return FALSE; |
return TRUE; |
} |
/* getSlideShowTitle |
returns the slide show title from UI. |
*/ |
-(NSString*)getSlideShowTitle{ |
return [gSlideshowTitleField stringValue]; |
} |
/* getTransitionName |
fxCategory = filled in with the effect category of the return transition. |
index = index in the popup for which you want the name and fx category. |
returns the name of the transition at index in the popup |
*/ |
-(NSString*)getTransitionName: (NSString**)fxCategory forIndex:(int)index{ |
NSString *curTrans =[gTransitionSelectionField itemTitleAtIndex: index]; |
if (NSOrderedSame == [curTrans compare:@"random"]){ |
NSLog(@"we got the index for random in getTransitionName:forIndex"); |
*fxCategory =@"Dissolve"; |
return @"Cross Dissolve"; |
} |
if (NSOrderedSame == [curTrans compare:@"Cross Dissolve"]){ |
*fxCategory =@"Dissolve"; |
} else if (NSOrderedSame == [curTrans compare:@"Edge Wipe"]){ |
*fxCategory =@"Wipe"; |
} else *fxCategory =@"Iris"; |
return curTrans; |
} |
/* getTransitionName |
effectCategory = filled in with the effect category of the return transition. |
returns the name of the selected transition or if "(random)" is selected, |
a random transition from the popup. |
*/ |
-(NSString*)getTransitionName: (NSString**)fxCategory{ |
int index = [gTransitionSelectionField indexOfSelectedItem]; |
if (index == gIndexOfRandom){ |
index = random()%(gIndexOfRandom);//+1? |
} |
return [self getTransitionName:fxCategory forIndex:index]; |
} |
/* getFilesCount |
returns a count of the number of files in the selected iPhoto Album |
*/ |
-(int)getFilesCount{ |
CFIndex fileCount = CFArrayGetCount((CFArrayRef)gKeysForAlbum); |
return (int)fileCount; |
} |
/* getClipFileURL |
index = the index of the file (in the file array) to get the URL and/or name for. |
andName = the name of the file at index. |
returns a the pathURL string of the file at index in the selected iPhoto Album |
*/ |
-(NSString*)getClipFileURL:(int)index andName:(NSString**)clipName{ |
//get the key value to lookup |
CFStringRef currentKey = CFArrayGetValueAtIndex((CFArrayRef)gKeysForAlbum, index); |
//find the keyed entry in the master image dictionary |
CFDictionaryRef currClipDataDict = nil; |
if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)gMasterImageDictList, currentKey, (const void**)&currClipDataDict)){ |
return nil; |
} |
//get the fileurl stored at "imagepath" |
NSString *filePath = nil,*fileURL = nil; |
if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)currClipDataDict, @"ImagePath", (const void**)&filePath)){ |
return nil; |
} |
//get the name to use in finalcut for this image stored at "Caption" |
if (!CFDictionaryGetValueIfPresent((CFDictionaryRef)currClipDataDict, @"Caption", (const void**)clipName)){ |
NSFileManager *fileManager = [NSFileManager defaultManager]; |
*clipName = [fileManager displayNameAtPath:filePath]; |
} |
//make sure the url is properly percent escaped by making a URL and then converting that back to a string. |
if (filePath != nil){ |
NSURL *urlurl = [NSURL fileURLWithPath:filePath]; |
fileURL = (NSString*)CFURLGetString((CFURLRef)urlurl); |
} |
return fileURL; |
} |
@end |
Copyright © 2008 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2008-05-15