Added:
EyeTunes/trunk/ETPlaylistCache.h
EyeTunes/trunk/ETPlaylistCache.m
EyeTunes/trunk/ETRootUserPlaylist.h
EyeTunes/trunk/ETRootUserPlaylist.m
EyeTunes/trunk/NSNumber+ETPlaylistNameSorting.h
EyeTunes/trunk/NSNumber+ETPlaylistNameSorting.m
Modified:
EyeTunes/trunk/DebugController.h
EyeTunes/trunk/DebugController.m
EyeTunes/trunk/ETEyeTunes.h
EyeTunes/trunk/ETEyeTunes.m
EyeTunes/trunk/ETPlaylist.h
EyeTunes/trunk/ETPlaylist.m
EyeTunes/trunk/EyeTunes.h
EyeTunes/trunk/EyeTunes.xcodeproj/project.pbxproj
EyeTunes/trunk/EyeTunesEventCodes.h
EyeTunes/trunk/MainMenu.nib/classes.nib
EyeTunes/trunk/MainMenu.nib/info.nib
EyeTunes/trunk/MainMenu.nib/keyedobjects.nib
Log:
This is a bigger change. I added a playlist cache so that the playlist
hierarchy can be coerced into the tree structure that iTunes displays. This
cache must be rebuild whenever iTunes' playlists could have changed. If in
doubt, simply do so. The 'Library' and 'Genius' playlists will show up as
user playlists. This is an iTunes bug, I will file a radar bug on it.
As a bonus I added an outline view to the test/demo app to show how this
can be used in your own app.
I hope I didn't break the backwards compatibility. If yes, please let me
know or submit a patch.
Thanks Ruotger
Modified: EyeTunes/trunk/DebugController.h
==============================================================================
--- EyeTunes/trunk/DebugController.h (original)
+++ EyeTunes/trunk/DebugController.h Fri Nov 14 06:36:32 2008
@@ -21,6 +21,8 @@
IBOutlet NSTextField *albumName;
IBOutlet NSTextField *artistName;
IBOutlet NSTextField *trackName;
+
+ IBOutlet NSOutlineView *outlineView;
}
- (IBAction) prev:(id)sender;
Modified: EyeTunes/trunk/DebugController.m
==============================================================================
--- EyeTunes/trunk/DebugController.m (original)
+++ EyeTunes/trunk/DebugController.m Fri Nov 14 06:36:32 2008
@@ -9,7 +9,6 @@
#import <Cocoa/Cocoa.h>
#import "DebugController.h"
-
@implementation DebugController
@@ -60,7 +59,8 @@
[[EyeTunes sharedInstance] versionNumber];
-
+ [ETPlaylistCache sharedInstance];
+ [outlineView reloadData];
}
- (IBAction) prev:(id)sender
@@ -93,9 +93,10 @@
{
ETPlaylist * playlist = [playlists objectAtIndex:i];
[self _append:[playlist name]];
+ [self _append:[NSString stringWithFormat:@" (%@)", [playlist
stringForOSType:[playlist specialKind]]]];
ETPlaylist * parentPlaylist = [playlist parentPlaylist];
if (parentPlaylist)
- [self _append:[NSString stringWithFormat:@" --- parent: %@",
[parentPlaylist name]]];
+ [self _append:[NSString stringWithFormat:@" --- parent: %@",
[parentPlaylist name]]];
[self _append:@"\n"];
}
}
@@ -219,6 +220,50 @@
[trackName setStringValue:[NSString stringWithFormat:@"track
name: %@",[track name]]];
[albumName setStringValue:[NSString stringWithFormat:@"album
name: %@",[track album]]];
[artistName setStringValue:[NSString stringWithFormat:@"artist
name: %@",[track artist]]];
+}
+
+
+- (id)outlineView:(NSOutlineView *)outlineView child:(int)index
ofItem:(id)item
+{
+ ETPlaylist * playlist = (ETPlaylist*)item;
+ if (!playlist)
+ playlist = [[EyeTunes sharedInstance] rootPlaylist];
+
+ if (![playlist isKindOfClass:[ETPlaylist class]])
+ return nil;
+
+ NSNumber * playlistId = [[playlist childPlaylistIds] objectAtIndex:index];
+ return [[ETPlaylistCache sharedInstance]
playlistForPersistentId:[playlistId longLongValue]];
+}
+
+- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
+{
+ if (![item isKindOfClass:[ETPlaylist class]])
+ return NO;
+
+ return [[(ETPlaylist*)item childPlaylistIds] count];
+}
+
+- (int)outlineView:(NSOutlineView *)outlineView
numberOfChildrenOfItem:(id)item
+{
+ if (!item)
+ {
+ ETPlaylist * rootPlaylist = [[EyeTunes sharedInstance] rootPlaylist];
+ return [[rootPlaylist childPlaylistIds] count];
+ }
+
+ if (![item isKindOfClass:[ETPlaylist class]])
+ return 0;
+
+ return [[(ETPlaylist*)item childPlaylistIds] count];
+}
+
+- (id)outlineView:(NSOutlineView *)outlineView
objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item
+{
+ if (![item isKindOfClass:[ETPlaylist class]])
+ return @"wrong class";
+
+ return [(ETPlaylist*)item name];
}
@end
Modified: EyeTunes/trunk/ETEyeTunes.h
==============================================================================
--- EyeTunes/trunk/ETEyeTunes.h (original)
+++ EyeTunes/trunk/ETEyeTunes.h Fri Nov 14 06:36:32 2008
@@ -50,6 +50,9 @@
// things that return a Track object
- (NSArray *)search:(ETPlaylist *)playlist forString:(NSString
*)searchString inField:(DescType)typeCode;
+// get root playlist
+- (ETPlaylist*) rootPlaylist;
+
// get all playlists
- (int)playlistCount;
- (NSArray *)playlists;
Modified: EyeTunes/trunk/ETEyeTunes.m
==============================================================================
--- EyeTunes/trunk/ETEyeTunes.m (original)
+++ EyeTunes/trunk/ETEyeTunes.m Fri Nov 14 06:36:32 2008
@@ -41,6 +41,7 @@
#import "ETPlaylist.h"
#import "ETPlaylistEnumerator.h"
#import "ETUserPlaylistEnumerator.h"
+#import "ETPlaylistCache.h"
#import "ETDebug.h"
@@ -614,6 +615,14 @@
}
+
+- (ETPlaylist*) rootPlaylist;
+{
+ // this call returns the root playlist. this playlist is a pseudo
playlist and simply contains the categories
+ return [[ETPlaylistCache sharedInstance] playlistForPersistentId:0];
+}
+
+
- (int) playlistCount
{
return [self getCountOfElementsOfClass:ET_CLASS_PLAYLIST];
@@ -633,7 +642,7 @@
- (int)userPlaylistCount;
{
- // I know this is not very elegant since we can't use
getCountOfElementsOfClass here
+ // this is not very elegant since we can't use getCountOfElementsOfClass
here
// just don't use it, Ruotger
return [[self userPlaylists] count];
}
Modified: EyeTunes/trunk/ETPlaylist.h
==============================================================================
--- EyeTunes/trunk/ETPlaylist.h (original)
+++ EyeTunes/trunk/ETPlaylist.h Fri Nov 14 06:36:32 2008
@@ -40,20 +40,37 @@
@class ETTrackEnumerator;
@class ETTrack;
-@interface ETPlaylist : ETAppleEventObject {
+@interface ETPlaylist : ETAppleEventObject
+{
+ NSMutableArray * childPlaylistIds;
+ BOOL areChildrenSorted;
+ BOOL isSpecialKind;
+ BOOL isCached;
+ unsigned long long persistentId;
+ unsigned long long parentPlaylistId;
}
- (id) initWithDescriptor:(AEDesc *)desc;
- (NSString *)name;
- (DescType) specialKind;
+- (BOOL) isSpecialKind;
+- (BOOL) isCached;
+
+- (unsigned long long) parentPlaylistId;
+- (void) setParentPlaylistId:(unsigned long long)inParentPlaylistID;
+- (ETPlaylist*) parentPlaylist;
+- (NSArray*) childPlaylistIds;
+- (void) addChildPlaylistId:(NSNumber*)childPlaylistId;
- (NSArray *)tracks;
- (int) trackCount;
- (NSEnumerator *)trackEnumerator;
- (ETTrack *)trackWithDatabaseId:(int)databaseId;
+- (void) setPersistentId:(long long int)inPersistentID;
- (long long int)persistentId;
+- (NSNumber*)persistentIdNumber;
- (NSString *) persistentIdAsString;
- (ETTrack *)trackWithPersistentId:(long long int)persistentId;
Modified: EyeTunes/trunk/ETPlaylist.m
==============================================================================
--- EyeTunes/trunk/ETPlaylist.m (original)
+++ EyeTunes/trunk/ETPlaylist.m Fri Nov 14 06:36:32 2008
@@ -47,14 +47,28 @@
@implementation ETPlaylist
+
+
- (id) initWithDescriptor:(AEDesc *)desc
{
- self = [super initWithDescriptor:desc
applCode:ET_APPLE_EVENT_OBJECT_DEFAULT_APPL];
+ if (![super initWithDescriptor:desc
applCode:ET_APPLE_EVENT_OBJECT_DEFAULT_APPL])
+ return nil;
+
+ parentPlaylistId = -1;
+ persistentId = -1;
return self;
}
- (NSString *)name
{
+ if ([self persistentId] == kETSpecialPlaylistRoot)
+ return NSLocalizedString(@"iTunes", @"EyeTunes root playlist name");
+ if ([self persistentId] == kETSpecialPlaylistCategoryLibrary)
+ return NSLocalizedString(@"LIBRARY", @"EyeTunes category playlist name");
+ if ([self persistentId] == kETSpecialPlaylistCategoryStore)
+ return NSLocalizedString(@"STORE", @"EyeTunes category playlist name");
+ if ([self persistentId] == kETSpecialPlaylistCategoryPlaylists)
+ return NSLocalizedString(@"PLAYLISTS", @"EyeTunes category playlist
name");
return [self getPropertyAsStringForDesc:ET_ITEM_PROP_NAME];
}
@@ -112,6 +126,41 @@
return parentPlaylist;
}
+- (unsigned long long) parentPlaylistId;
+{
+ if (parentPlaylistId == -1)
+ {
+ parentPlaylistId = [[self parentPlaylist] persistentId];
+ }
+ return parentPlaylistId;
+}
+
+// we need to be able to overwrite this value to move the playlist to a
different location in the tree
+- (void) setParentPlaylistId:(unsigned long long)inParentPlaylistId;
+{
+ parentPlaylistId = inParentPlaylistId;
+}
+
+- (NSArray*) childPlaylistIds;
+{
+ if (!areChildrenSorted)
+ {
+ [childPlaylistIds sortUsingSelector:@selector(comparePlaylistName:)];
+ areChildrenSorted = YES;
+ }
+
+ return [NSArray arrayWithArray:childPlaylistIds];
+}
+
+
+- (void) addChildPlaylistId:(NSNumber*)childPlaylistId;
+{
+ if (!childPlaylistIds)
+ childPlaylistIds = [[NSMutableArray alloc] init];
+
+ [childPlaylistIds addObject:childPlaylistId];
+ areChildrenSorted = NO;
+}
- (NSEnumerator *)trackEnumerator
@@ -145,7 +194,7 @@
return foundTrack;
}
-- (ETTrack *)trackWithPersistentId:(long long int)persistentId
+- (ETTrack *)trackWithPersistentId:(long long int)inPersistentId
{
if ([[EyeTunes sharedInstance] versionLessThan:ITUNES_6_0])
return nil;
@@ -157,12 +206,12 @@
[[EyeTunes sharedInstance] versionLessThan:ITUNES_7_2]) {
replyEvent = [self getElementOfClass:ET_CLASS_TRACK
byKey:ET_ITEM_PROP_PERSISTENT_ID
- withLongIntValue:persistentId];
+ withLongIntValue:inPersistentId];
}
else {
replyEvent = [self getElementOfClass:ET_CLASS_TRACK
byKey:ET_ITEM_PROP_PERSISTENT_ID
- withStringValue:[NSString stringWithFormat:@"%016llX",
persistentId]];
+ withStringValue:[NSString stringWithFormat:@"%016llX",
inPersistentId]];
}
/* Read Results */
AEDesc replyObject;
@@ -182,7 +231,7 @@
return foundTrack;
}
-- (ETTrack *)trackWithPersistentIdString:(NSString *)persistentId
+- (ETTrack *)trackWithPersistentIdString:(NSString *)inPersistentId
{
if ([[EyeTunes sharedInstance] versionLessThan:ITUNES_6_0])
return nil;
@@ -194,12 +243,12 @@
[[EyeTunes sharedInstance] versionLessThan:ITUNES_7_2]) {
replyEvent = [self getElementOfClass:ET_CLASS_TRACK
byKey:ET_ITEM_PROP_PERSISTENT_ID
- withLongIntValue:[persistentId longlongValue]];
+ withLongIntValue:[inPersistentId longlongValue]];
}
else {
replyEvent = [self getElementOfClass:ET_CLASS_TRACK
byKey:ET_ITEM_PROP_PERSISTENT_ID
- withStringValue:persistentId];
+ withStringValue:inPersistentId];
}
/* Read Results */
AEDesc replyObject;
@@ -220,8 +269,17 @@
}
+- (void) setPersistentId:(long long int)inPersistentId;
+{
+ persistentId = inPersistentId;
+}
+
+
- (long long int) persistentId
{
+ if (persistentId != -1)
+ return persistentId;
+
if ([[EyeTunes sharedInstance] versionLessThan:ITUNES_6_0]) {
ETLog(@"persistentId Unsupported");
return -1;
@@ -231,11 +289,17 @@
[[EyeTunes sharedInstance] versionLessThan:ITUNES_7_2])
return [self
getPropertyAsLongIntegerForDesc:ET_ITEM_PROP_PERSISTENT_ID];
else {
- NSString *persistentId = [NSString stringWithFormat:@"0x%@",[self
getPropertyAsStringForDesc:ET_ITEM_PROP_PERSISTENT_ID]];
- return [persistentId longlongValue];
+ NSString *persistentIDString = [NSString stringWithFormat:@"0x%@",[self
getPropertyAsStringForDesc:ET_ITEM_PROP_PERSISTENT_ID]];
+ persistentId = [persistentIDString longlongValue];
+ return persistentId;
}
}
+- (NSNumber*)persistentIdNumber;
+{
+ return [NSNumber numberWithLongLong:[self persistentId]];
+}
+
- (NSString *) persistentIdAsString
{
@@ -249,6 +313,19 @@
return [[NSString stringWithFormat:@"%016llX",[self
getPropertyAsLongIntegerForDesc:ET_ITEM_PROP_PERSISTENT_ID]]
uppercaseString];
else
return [self getPropertyAsStringForDesc:ET_ITEM_PROP_PERSISTENT_ID];
+}
+
+
+- (BOOL) isSpecialKind;
+{
+ NSLog (@"WARNING: not yet implemented");
+ return NO;
+}
+
+- (BOOL) isCached;
+{
+ NSLog (@"WARNING: not yet implemented");
+ return NO;
}
@end
Added: EyeTunes/trunk/ETPlaylistCache.h
==============================================================================
--- (empty file)
+++ EyeTunes/trunk/ETPlaylistCache.h Fri Nov 14 06:36:32 2008
@@ -0,0 +1,23 @@
+//
+// ETPlaylistCache.h
+// EyeTunes
+//
+// Created by Ruotger Skupin on 26.09.08.
+// Copyright 2008 __MyCompanyName__. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+@class ETPlaylist;
+
+@interface ETPlaylistCache : NSObject
+{
+ NSMutableDictionary * playlists;
+}
+
++ (id) sharedInstance;
+
+- (void) reload;
+- (ETPlaylist*) playlistForPersistentId:(long long int)persistentId;
+- (ETPlaylist*) rootUserPlaylist;
+@end
Added: EyeTunes/trunk/ETPlaylistCache.m
==============================================================================
--- (empty file)
+++ EyeTunes/trunk/ETPlaylistCache.m Fri Nov 14 06:36:32 2008
@@ -0,0 +1,160 @@
+//
+// ETPlaylistCache.m
+// EyeTunes
+//
+// Created by Ruotger Skupin on 26.09.08.
+// Copyright 2008 __MyCompanyName__. All rights reserved.
+//
+
+#import "ETPlaylistCache.h"
+#import "ETPlaylist.h"
+#import "ETPlaylistEnumerator.h"
+
+// this class caches all playlists and builds the playlist tree. Every
playlist only knows its parent,
+// so we have to iterate through all playlists and the children ids to
their parents
+
+@implementation ETPlaylistCache
+
++ (id) sharedInstance;
+{
+ static ETPlaylistCache * sharedInstance = nil;
+ if (!sharedInstance)
+ {
+ sharedInstance = [[ETPlaylistCache alloc] init];
+ [sharedInstance reload];
+ }
+
+ return sharedInstance;
+}
+
+- (id) init
+{
+ if (![super init])
+ return nil;
+
+ playlists = [[NSMutableDictionary alloc] init];
+
+ return self;
+}
+
+
+- (void) reload;
+{
+ [playlists removeAllObjects];
+
+ ETPlaylistEnumerator * en = [[[ETPlaylistEnumerator alloc] init]
autorelease];
+
+ ETPlaylist * rootPlaylist = [[[ETPlaylist alloc] init] autorelease];
+ [rootPlaylist setPersistentId:kETSpecialPlaylistRoot];
+ [playlists setObject:rootPlaylist forKey:[NSNumber
numberWithLongLong:kETSpecialPlaylistRoot]];
+
+ // category playlists
+ ETPlaylist * libraryCategory = [[[ETPlaylist alloc] init] autorelease];
+ [libraryCategory setParentPlaylistId:kETSpecialPlaylistRoot];
+ [libraryCategory setPersistentId:kETSpecialPlaylistCategoryLibrary];
+ [playlists setObject:libraryCategory forKey:[NSNumber
numberWithLongLong:kETSpecialPlaylistCategoryLibrary]];
+
+ ETPlaylist * storeCategory = [[[ETPlaylist alloc] init] autorelease];
+ [storeCategory setParentPlaylistId:kETSpecialPlaylistRoot];
+ [storeCategory setPersistentId:kETSpecialPlaylistCategoryStore];
+ [playlists setObject:storeCategory forKey:[NSNumber
numberWithLongLong:kETSpecialPlaylistCategoryStore]];
+
+ ETPlaylist * playlistsCategory = [[[ETPlaylist alloc] init] autorelease];
+ [playlistsCategory setParentPlaylistId:kETSpecialPlaylistRoot];
+ [playlistsCategory setPersistentId:kETSpecialPlaylistCategoryPlaylists];
+ [playlists setObject:playlistsCategory forKey:[NSNumber
numberWithLongLong:kETSpecialPlaylistCategoryPlaylists]];
+
+ // add all playlists
+ ETPlaylist * playlist = nil;
+ while ((playlist = [en nextObject]))
+ {
+ [playlists setObject:playlist forKey:[NSNumber
numberWithLongLong:[playlist persistentId]]];
+ }
+
+ // find special playlists
+ NSEnumerator * en2 = [playlists objectEnumerator];
+ unsigned int count = 0;
+ while ((playlist = [en2 nextObject]))
+ {
+ count++;
+ if ([playlist persistentId] >= 0 && [playlist persistentId] <= 3) //
root or categories
+ continue;
+
+ /*
+ if ([playlist persistentId] == 6554597091219814194ll) // not sure that
this is a good idea...
+ {
+ mediathek = playlist;
+ continue;
+ }
+ if ([playlist persistentId] == 6114773995509758539ll) // not sure that
this is a good idea...
+ {
+ genius = playlist;
+ continue;
+ }
+*/
+ NSLog (@"playlist: %@ (%@)", [playlist name], [playlist
stringForOSType:[playlist specialKind]]);
+
+ switch ([playlist specialKind])
+ {
+ case kETSpecialPlaylistPodcasts:
+ case kETSpecialPlaylistVideo:
+ case kETSpecialPlaylistAudiobooks:
+ case kETSpecialPlaylistMovies:
+ case kETSpecialPlaylistMusic:
+ case kETSpecialPlaylistTVShows:
+ [playlist setParentPlaylistId:kETSpecialPlaylistCategoryLibrary];
+ break;
+
+ case kETSpecialPlaylistPurchasedMusic:
+ [playlist setParentPlaylistId:kETSpecialPlaylistCategoryStore];
+ break;
+
+ case kETSpecialPlaylistPartyShuffle:
+ [playlist setParentPlaylistId:kETSpecialPlaylistCategoryPlaylists];
+ break;
+
+ case kETSpecialPlaylistNone:
+ case kETSpecialPlaylistFolder:
+ {
+ ETPlaylist * parentPlaylist = [playlist parentPlaylist];
+ long long parentPersistentId = [parentPlaylist persistentId];
+ if (!parentPersistentId)
+ [playlist setParentPlaylistId:kETSpecialPlaylistCategoryPlaylists];
+ else
+ [playlist setParentPlaylistId:parentPersistentId];
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // add children
+ en2 = [playlists objectEnumerator];
+ while ((playlist = [en2 nextObject]))
+ {
+ unsigned long long playlistPersistentID = [playlist persistentId];
+ NSString * playlistName = [playlist name];
+ if (playlistPersistentID == 0) // root
+ continue;
+
+ long long parentPersistentId = [playlist parentPlaylistId];
+
+ ETPlaylist * parentPlaylist = (parentPersistentId != 0) ? [self
playlistForPersistentId:parentPersistentId] : rootPlaylist;
+ NSLog (@"playlist: %@ (%@) [%qi] -- parent: %@", playlistName, [playlist
stringForOSType:[playlist specialKind]], [playlist persistentId],
[parentPlaylist name]);
+ [parentPlaylist addChildPlaylistId:[playlist persistentIdNumber]];
+ }
+}
+
+- (ETPlaylist*) playlistForPersistentId:(long long int)persistentId;
+{
+ return [playlists objectForKey:[NSNumber
numberWithLongLong:persistentId]];
+}
+
+
+- (ETPlaylist*) rootUserPlaylist;
+{
+ return nil;
+}
+@end
Added: EyeTunes/trunk/ETRootUserPlaylist.h
==============================================================================
--- (empty file)
+++ EyeTunes/trunk/ETRootUserPlaylist.h Fri Nov 14 06:36:32 2008
@@ -0,0 +1,17 @@
+//
+// ETRootUserPlaylist.h
+// EyeTunes
+//
+// Created by Ruotger Skupin on 04.10.08.
+// Copyright 2008 __MyCompanyName__. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+#import "ETPlaylist.h"
+
+@interface ETRootUserPlaylist : ETPlaylist
+{
+
+}
+
+@end
Added: EyeTunes/trunk/ETRootUserPlaylist.m
==============================================================================
--- (empty file)
+++ EyeTunes/trunk/ETRootUserPlaylist.m Fri Nov 14 06:36:32 2008
@@ -0,0 +1,14 @@
+//
+// ETRootUserPlaylist.m
+// EyeTunes
+//
+// Created by Ruotger Skupin on 04.10.08.
+// Copyright 2008 __MyCompanyName__. All rights reserved.
+//
+
+#import "ETRootUserPlaylist.h"
+
+
+@implementation ETRootUserPlaylist
+
+@end
Modified: EyeTunes/trunk/EyeTunes.h
==============================================================================
--- EyeTunes/trunk/EyeTunes.h (original)
+++ EyeTunes/trunk/EyeTunes.h Fri Nov 14 06:36:32 2008
@@ -58,3 +58,4 @@
#import "ETEyeTunes.h"
#import "ETTrack.h"
#import "ETPlaylist.h"
+#import "ETPlaylistCache.h"
Modified: EyeTunes/trunk/EyeTunes.xcodeproj/project.pbxproj
==============================================================================
--- EyeTunes/trunk/EyeTunes.xcodeproj/project.pbxproj (original)
+++ EyeTunes/trunk/EyeTunes.xcodeproj/project.pbxproj Fri Nov 14 06:36:32
2008
@@ -50,7 +50,13 @@
039620C80C0DE7CC00786326 /* EyeTunes.framework in Frameworks */ = {isa =
PBXBuildFile; fileRef = 8DC2EF5B0486A6940098B216 /* EyeTunes.framework */;
};
8DC2EF530486A6940098B216 /* InfoPlist.strings in Resources */ = {isa =
PBXBuildFile; fileRef = 089C1666FE841158C02AAC07 /* InfoPlist.strings */; };
DD233EB70E66FD45004B210F /* ETUserPlaylistEnumerator.m in Sources */ =
{isa = PBXBuildFile; fileRef = DD233EAB0E66FCC4004B210F /*
ETUserPlaylistEnumerator.m */; };
- DD233EB80E66FD45004B210F /* ETUserPlaylistEnumerator.h in Headers */ =
{isa = PBXBuildFile; fileRef = DD233EAA0E66FCC4004B210F /*
ETUserPlaylistEnumerator.h */; };
+ DD233EB80E66FD45004B210F /* ETUserPlaylistEnumerator.h in Headers */ =
{isa = PBXBuildFile; fileRef = DD233EAA0E66FCC4004B210F /*
ETUserPlaylistEnumerator.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ DDB3AF3D0EC4A147003C7FE6 /* ETRootUserPlaylist.m in Sources */ = {isa =
PBXBuildFile; fileRef = DD2AB89A0E97A88800178457 /* ETRootUserPlaylist.m
*/; };
+ DDB3AF3E0EC4A148003C7FE6 /* ETRootUserPlaylist.h in Headers */ = {isa =
PBXBuildFile; fileRef = DD2AB8990E97A88800178457 /* ETRootUserPlaylist.h
*/; settings = {ATTRIBUTES = (Public, ); }; };
+ DDEBCC900E8D1EF600219086 /* ETPlaylistCache.m in Sources */ = {isa =
PBXBuildFile; fileRef = DDEBCBB70E8D0DAD00219086 /* ETPlaylistCache.m */; };
+ DDEBCC910E8D1EF700219086 /* ETPlaylistCache.h in Headers */ = {isa =
PBXBuildFile; fileRef = DDEBCBB60E8D0DAD00219086 /* ETPlaylistCache.h */;
settings = {ATTRIBUTES = (Public, ); }; };
+ DDEBCD350E8D255600219086 /* NSNumber+ETPlaylistNameSorting.h in Headers
*/ = {isa = PBXBuildFile; fileRef = DDEBCD320E8D245000219086 /*
NSNumber+ETPlaylistNameSorting.h */; settings = {ATTRIBUTES = (Public, );
}; };
+ DDEBCD360E8D255600219086 /* NSNumber+ETPlaylistNameSorting.m in Sources
*/ = {isa = PBXBuildFile; fileRef = DDEBCD330E8D245000219086 /*
NSNumber+ETPlaylistNameSorting.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@@ -113,6 +119,12 @@
8DC2EF5B0486A6940098B216 /* EyeTunes.framework */ = {isa =
PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0;
path = EyeTunes.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DD233EAA0E66FCC4004B210F /* ETUserPlaylistEnumerator.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;
path = ETUserPlaylistEnumerator.h; sourceTree = "<group>"; };
DD233EAB0E66FCC4004B210F /* ETUserPlaylistEnumerator.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc;
path = ETUserPlaylistEnumerator.m; sourceTree = "<group>"; };
+ DD2AB8990E97A88800178457 /* ETRootUserPlaylist.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;
path = ETRootUserPlaylist.h; sourceTree = "<group>"; };
+ DD2AB89A0E97A88800178457 /* ETRootUserPlaylist.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc;
path = ETRootUserPlaylist.m; sourceTree = "<group>"; };
+ DDEBCBB60E8D0DAD00219086 /* ETPlaylistCache.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;
path = ETPlaylistCache.h; sourceTree = "<group>"; };
+ DDEBCBB70E8D0DAD00219086 /* ETPlaylistCache.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc;
path = ETPlaylistCache.m; sourceTree = "<group>"; };
+ DDEBCD320E8D245000219086 /* NSNumber+ETPlaylistNameSorting.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h;
path = "NSNumber+ETPlaylistNameSorting.h"; sourceTree = "<group>"; };
+ DDEBCD330E8D245000219086 /* NSNumber+ETPlaylistNameSorting.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc;
path = "NSNumber+ETPlaylistNameSorting.m"; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -237,12 +249,18 @@
032E44AE098A4F2B00C55ECB /* ETTrackEnumerator.m */,
032E476A098A8FDF00C55ECB /* ETPlaylistEnumerator.h */,
032E476B098A8FDF00C55ECB /* ETPlaylistEnumerator.m */,
+ DD2AB8990E97A88800178457 /* ETRootUserPlaylist.h */,
+ DD2AB89A0E97A88800178457 /* ETRootUserPlaylist.m */,
DD233EAA0E66FCC4004B210F /* ETUserPlaylistEnumerator.h */,
DD233EAB0E66FCC4004B210F /* ETUserPlaylistEnumerator.m */,
030BF9AB098CFFD100D68616 /* ETDebug.h */,
030BF9AC098CFFD100D68616 /* ETDebug.m */,
039620970C0DE71600786326 /* NSString+LongLongValue.h */,
039620980C0DE71600786326 /* NSString+LongLongValue.m */,
+ DDEBCBB60E8D0DAD00219086 /* ETPlaylistCache.h */,
+ DDEBCBB70E8D0DAD00219086 /* ETPlaylistCache.m */,
+ DDEBCD320E8D245000219086 /* NSNumber+ETPlaylistNameSorting.h */,
+ DDEBCD330E8D245000219086 /* NSNumber+ETPlaylistNameSorting.m */,
);
name = Classes;
sourceTree = "<group>";
@@ -291,6 +309,9 @@
0313DDED0C10DFB400F401BB /* ETEyeTunes.h in Headers */,
0313DE1D0C10E09900F401BB /* EyeTunesVersions.h in Headers */,
DD233EB80E66FD45004B210F /* ETUserPlaylistEnumerator.h in Headers */,
+ DDEBCD350E8D255600219086 /* NSNumber+ETPlaylistNameSorting.h in
Headers */,
+ DDEBCC910E8D1EF700219086 /* ETPlaylistCache.h in Headers */,
+ DDB3AF3E0EC4A148003C7FE6 /* ETRootUserPlaylist.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -420,15 +441,18 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
- 035B70BA0885537800D0B89E /* ETTrack.m in Sources */,
032CE8560886594100F33185 /* ETAppleEventObject.m in Sources */,
- 032CEB750886E48100F33185 /* ETPlaylist.m in Sources */,
- 032E44B1098A4F2C00C55ECB /* ETTrackEnumerator.m in Sources */,
- 032E476E098A8FDF00C55ECB /* ETPlaylistEnumerator.m in Sources */,
030BF9AE098CFFD100D68616 /* ETDebug.m in Sources */,
- 0396209A0C0DE71600786326 /* NSString+LongLongValue.m in Sources */,
0313DE490C10E1ED00F401BB /* ETEyeTunes.m in Sources */,
+ 032CEB750886E48100F33185 /* ETPlaylist.m in Sources */,
+ DDEBCC900E8D1EF600219086 /* ETPlaylistCache.m in Sources */,
+ 032E476E098A8FDF00C55ECB /* ETPlaylistEnumerator.m in Sources */,
+ DDB3AF3D0EC4A147003C7FE6 /* ETRootUserPlaylist.m in Sources */,
+ 035B70BA0885537800D0B89E /* ETTrack.m in Sources */,
+ 032E44B1098A4F2C00C55ECB /* ETTrackEnumerator.m in Sources */,
DD233EB70E66FD45004B210F /* ETUserPlaylistEnumerator.m in Sources */,
+ DDEBCD360E8D255600219086 /* NSNumber+ETPlaylistNameSorting.m in
Sources */,
+ 0396209A0C0DE71600786326 /* NSString+LongLongValue.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -463,6 +487,7 @@
FRAMEWORK_VERSION = A;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_ENABLE_OBJC_GC = YES;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
Modified: EyeTunes/trunk/EyeTunesEventCodes.h
==============================================================================
--- EyeTunes/trunk/EyeTunesEventCodes.h (original)
+++ EyeTunes/trunk/EyeTunesEventCodes.h Fri Nov 14 06:36:32 2008
@@ -100,6 +100,13 @@
}; // ET_PLAYLIST_SPECIAL_KIND (eSpK)
#endif
+enum {
+ kETSpecialPlaylistRoot = 0,
+ kETSpecialPlaylistCategoryLibrary = 1,
+ kETSpecialPlaylistCategoryStore = 2,
+ kETSpecialPlaylistCategoryPlaylists = 3,
+};
+
#if ITUNES_VERSION >= ITUNES_7_0
enum {
kETVideoKindUnknown = 'kVdN',
@@ -276,4 +283,5 @@
#define ET_CLASS_DEVICE_PLAYLIST 'cDvP' // <class name="device playlist"
code="cDvP" description="a playlist representing the contents of a portable
device" inherits="playlist" plural="device playlists">
#define ET_CLASS_FOLDER_PLAYLIST 'cFoP' // <class name="folder playlist"
code="cFoP" description="a folder that contains other playlists"
inherits="user playlist" plural="folder playlists"/>
#define ET_CLASS_USER_PLAYLIST 'cUsP' // <class name="user playlist"
code="cUsP" description="custom playlists created by the user"
inherits="playlist" plural="user playlists">
+#define ET_CLASS_RADIOTUNER_PLAYLIST 'cRTP' // <class name="radio tuner
playlist" code="cRTP" description="the radio tuner playlist"
inherits="playlist" plural="radio tuner playlists">
Modified: EyeTunes/trunk/MainMenu.nib/classes.nib
==============================================================================
--- EyeTunes/trunk/MainMenu.nib/classes.nib (original)
+++ EyeTunes/trunk/MainMenu.nib/classes.nib Fri Nov 14 06:36:32 2008
@@ -46,6 +46,8 @@
<string>NSImageView</string>
<key>nextButton</key>
<string>NSButton</string>
+ <key>outlineView</key>
+ <string>NSOutlineView</string>
<key>output</key>
<string>NSTextView</string>
<key>playButton</key>
Modified: EyeTunes/trunk/MainMenu.nib/info.nib
==============================================================================
--- EyeTunes/trunk/MainMenu.nib/info.nib (original)
+++ EyeTunes/trunk/MainMenu.nib/info.nib Fri Nov 14 06:36:32 2008
@@ -3,18 +3,18 @@
<plist version="1.0">
<dict>
<key>IBFramework Version</key>
- <string>670</string>
+ <string>672</string>
<key>IBLastKnownRelativeProjectPath</key>
<string>EyeTunes.xcodeproj</string>
<key>IBOldestOS</key>
<integer>5</integer>
<key>IBOpenObjects</key>
<array>
- <integer>2</integer>
+ <integer>21</integer>
<integer>29</integer>
</array>
<key>IBSystem Version</key>
- <string>9E17</string>
+ <string>9F33</string>
<key>targetFramework</key>
<string>IBCocoaFramework</string>
</dict>
Modified: EyeTunes/trunk/MainMenu.nib/keyedobjects.nib
==============================================================================
Binary files. No diff available.
Added: EyeTunes/trunk/NSNumber+ETPlaylistNameSorting.h
==============================================================================
--- (empty file)
+++ EyeTunes/trunk/NSNumber+ETPlaylistNameSorting.h Fri Nov 14 06:36:32 2008
@@ -0,0 +1,16 @@
+//
+// NSNumber+ETPlaylistNameSorting.h
+// EyeTunes
+//
+// Created by Ruotger Skupin on 26.09.08.
+// Copyright 2008 __MyCompanyName__. All rights reserved.
+//
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface NSNumber (ETPlaylistNameSorting)
+
+- (NSComparisonResult) comparePlaylistName:(NSNumber*)otherPersistentId;
+
+@end
Added: EyeTunes/trunk/NSNumber+ETPlaylistNameSorting.m
==============================================================================
--- (empty file)
+++ EyeTunes/trunk/NSNumber+ETPlaylistNameSorting.m Fri Nov 14 06:36:32 2008
@@ -0,0 +1,26 @@
+//
+// NSNumber+ETPlaylistNameSorting.m
+// EyeTunes
+//
+// Created by Ruotger Skupin on 26.09.08.
+// Copyright 2008 __MyCompanyName__. All rights reserved.
+//
+
+#import "NSNumber+ETPlaylistNameSorting.h"
+#import "ETPlaylistCache.h"
+#import "ETPlaylist.h"
+
+@implementation NSNumber (ETPlaylistNameSorting)
+
+- (NSComparisonResult) comparePlaylistName:(NSNumber*)otherPersistentId;
+{
+ ETPlaylist * ownPlaylist = [[ETPlaylistCache sharedInstance]
playlistForPersistentId:[self longLongValue]];
+ NSString * ownName = [ownPlaylist name];
+
+ ETPlaylist * otherPlaylist = [[ETPlaylistCache sharedInstance]
playlistForPersistentId:[otherPersistentId longLongValue]];
+ NSString * otherName = [otherPlaylist name];
+
+ return [ownName caseInsensitiveCompare:otherName];
+}
+
+@end