Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Photo Stream for iPhoto #41

Merged
merged 7 commits into from
Feb 10, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion IMBApertureParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,16 @@ - (BOOL) isAllPhotosAlbum:(NSDictionary*)inAlbumDict
}


//----------------------------------------------------------------------------------------------------------------------

// Returns whether the album dictionary provided represents the "Flagged" album

- (BOOL) isFlaggedAlbum:(NSDictionary*)inAlbumDict
{
return [[inAlbumDict objectForKey:@"uuid"] isEqualToString:@"flaggedAlbum"];
}


//----------------------------------------------------------------------------------------------------------------------


Expand Down Expand Up @@ -581,7 +591,8 @@ - (NSImage*) iconForAlbumType3:(NSString*)inType
{
static const IMBIconTypeMappingEntry kIconTypeMappingEntries[] =
{
{@"v3-Faces",@"sl-icon-small_people.tiff", @"folder", nil, nil},
{@"v3-Photo Stream",@"SL-stream.tiff", @"folder", nil, nil}, // photo stream
{@"v3-Faces",@"sl-icon-small_people.tiff", @"folder", nil, nil}, // faces
{@"v3-1", @"SL-album.tiff", @"folder", nil, nil}, // album
{@"v3-2", @"SL-smartAlbum.tiff", @"folder", nil, nil}, // smart album
{@"v3-3", @"SL-smartAlbum.tiff", @"folder", nil, nil}, // library **** ... 200X
Expand Down
19 changes: 14 additions & 5 deletions IMBAppleMediaParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,13 +82,15 @@
#define EVENTS_ID_SPACE @"EventId"
#define FACES_ID_SPACE @"FaceId"
#define ALBUMS_ID_SPACE @"AlbumId"
#define PHOTO_STREAM_ID_SPACE @"PhotoStreamId"

// Since we will add an events node to the list of iPhoto albums and a faces node to iPhoto and Aperture
// we have to create (sub-)ids for them that are unique throughout their library. The ones chosen below
// are very, very likely to be.

#define EVENTS_NODE_ID UINT_MAX-4811 // Very, very unlikely this not to be unique throughout library
#define FACES_NODE_ID UINT_MAX-4812 // Very, very unlikely this not to be unique throughout library
#define EVENTS_NODE_ID UINT_MAX-4811 // Very, very unlikely this not to be unique throughout library
#define FACES_NODE_ID UINT_MAX-4812 // Very, very unlikely this not to be unique throughout library
#define PHOTO_STREAM_NODE_ID UINT_MAX-4813 // Very, very unlikely this not to be unique throughout library

// node object types of interest for skimming

Expand Down Expand Up @@ -124,10 +126,13 @@ extern NSString* const kIMBiPhotoNodeObjectTypeFace; // = @"faces"

- (NSString*) identifierForId:(NSNumber*) inId inSpace:(NSString*) inIdSpace;

// Returns the standard album of all photos ("Photos") found in the XML data file.
// Also returns the index in the album list where the album was found.
// Returns the index of the all photos album ("Photos") in given album list

- (NSDictionary*) allPhotosAlbumInAlbumList:(NSArray*)inAlbumList atIndex:(NSNumber**)outIndex;
- (NSUInteger) indexOfAllPhotosAlbumInAlbumList:(NSArray*)inAlbumList;

// Returns the index of the flagged album ("Flagged") in given album list

- (NSUInteger) indexOfFlaggedAlbumInAlbumList:(NSArray*)inAlbumList;

// Returns whether inNode is the events node

Expand All @@ -137,6 +142,10 @@ extern NSString* const kIMBiPhotoNodeObjectTypeFace; // = @"faces"

- (BOOL) isFacesNode:(IMBNode*)inNode;

// Returns whether inNode is the Photo Stream node

- (BOOL) isPhotoStreamNode:(IMBNode*)inNode;

// Returns whether an album of this type exposes a disclosure triangle or not.
// Takes care of album Types "Folder", "Faces" and "Events".
// Subclass for more specific behavior.
Expand Down
158 changes: 121 additions & 37 deletions IMBAppleMediaParser.m
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ @interface IMBAppleMediaParser ()

- (NSString*) imagePathForImageKey:(NSString*)inImageKey;
- (NSString*) imagePathForFaceIndex:(NSNumber*)inFaceIndex inImageWithKey:(NSString*)inImageKey;

- (BOOL) supportsPhotoStreamFeatureInVersion:(NSString *)inVersion;
@end


Expand All @@ -105,22 +105,23 @@ @implementation IMBAppleMediaParser

- (void) addSpecialAlbumsToAlbumsInLibrary:(NSMutableDictionary*)inLibraryDict
{
NSArray* oldAlbumList = [inLibraryDict objectForKey:@"List of Albums"];
NSArray* oldAlbumList = [inLibraryDict objectForKey:@"List of Albums"];

if (oldAlbumList != nil && [oldAlbumList count]>0)
if (oldAlbumList != nil && [oldAlbumList count]>0)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

NSNumber* photosDictIndex = nil;
NSDictionary *photosDict = [self allPhotosAlbumInAlbumList:oldAlbumList atIndex:&photosDictIndex];
// To insert new albums like events and faces into the album list we have to re-create it mutable style
NSMutableArray *newAlbumList = [NSMutableArray arrayWithArray:oldAlbumList];

NSUInteger insertionIndex = [self indexOfAllPhotosAlbumInAlbumList:oldAlbumList];
NSDictionary *photosDict = nil;

if (photosDict && photosDictIndex)
if (insertionIndex != NSNotFound &&
(photosDict = [oldAlbumList objectAtIndex:insertionIndex]))
{
// To insert events and faces into the album list we have to re-create it mutable style
NSMutableArray *newAlbumList = [NSMutableArray arrayWithArray:oldAlbumList];

// events album right before photos album

// Events

if ([inLibraryDict objectForKey:@"List of Rolls"])
{
NSNumber *eventsId = [NSNumber numberWithUnsignedInt:EVENTS_NODE_ID];
Expand All @@ -132,9 +133,11 @@ - (void) addSpecialAlbumsToAlbumsInLibrary:(NSMutableDictionary*)inLibraryDict
@"Events", @"Album Type",
[photosDict objectForKey:@"Parent"], @"Parent", nil];

[newAlbumList insertObject:events atIndex:[photosDictIndex unsignedIntegerValue]];
// events album right before photos album

[newAlbumList insertObject:events atIndex:insertionIndex];
IMBRelease(events);
photosDictIndex = [NSNumber numberWithUnsignedInteger:[photosDictIndex unsignedIntegerValue] + 1];
insertionIndex++;
}

// Faces album right after photos album
Expand All @@ -150,13 +153,33 @@ - (void) addSpecialAlbumsToAlbumsInLibrary:(NSMutableDictionary*)inLibraryDict
@"Faces", @"Album Type",
[photosDict objectForKey:@"Parent"], @"Parent", nil];

[newAlbumList insertObject:faces atIndex:[photosDictIndex unsignedIntegerValue] + 1];
[newAlbumList insertObject:faces atIndex:insertionIndex + 1];
IMBRelease(faces);
}

// Replace the old albums array.
[inLibraryDict setValue:newAlbumList forKey:@"List of Albums"];
}

// Photo Stream album right before Flagged album

insertionIndex = [self indexOfFlaggedAlbumInAlbumList:newAlbumList];
if ([self supportsPhotoStreamFeatureInVersion:[inLibraryDict objectForKey:@"Application Version"]] &&
insertionIndex != NSNotFound)
{
NSNumber *albumId = [NSNumber numberWithUnsignedInt:PHOTO_STREAM_NODE_ID];
NSString *albumName = NSLocalizedStringWithDefaultValue(@"IMB.iPhotoParser.photostream", nil, IMBBundle(), @"Photo Stream", @"Photo Stream node shown in iPhoto library");

NSDictionary* album = [[NSDictionary alloc] initWithObjectsAndKeys:
albumId, @"AlbumId",
albumName, @"AlbumName",
@"Photo Stream", @"Album Type",
[photosDict objectForKey:@"Parent"], @"Parent", nil];

[newAlbumList insertObject:album atIndex:insertionIndex];
IMBRelease(album);
}

// Replace the old albums array.

[inLibraryDict setValue:newAlbumList forKey:@"List of Albums"];
[pool drain];
}
}
Expand Down Expand Up @@ -422,6 +445,28 @@ - (BOOL) isAllPhotosAlbum:(NSDictionary*)inAlbumDict
}


//----------------------------------------------------------------------------------------------------------------------
// Returns whether inAlbumDict is the "Flagged" album. Must be subclassed.

- (BOOL) isFlaggedAlbum:(NSDictionary*)inAlbumDict
{
NSLog(@"%s Please use a custom subclass of IMBAppleMediaParser...",__FUNCTION__);
[[NSException exceptionWithName:@"IMBProgrammerError" reason:@"Please use a custom subclass of IMBAppleMediaParser" userInfo:nil] raise];

return NO;
}


//----------------------------------------------------------------------------------------------------------------------
// Returns whether the parser supports Apple's Photo Stream feature
// (which is usually dependent on the data delivered through AlbumData.xml or ApertureData.xml respectively)

- (BOOL) supportsPhotoStreamFeatureInVersion:(NSString *)inVersion
{
return NO;
}


//----------------------------------------------------------------------------------------------------------------------

#pragma mark -
Expand Down Expand Up @@ -779,7 +824,10 @@ - (NSString*) idSpaceForAlbumType:(NSString*) inAlbumType
} else if ([inAlbumType isEqualToString:@"Face"] || [inAlbumType isEqualToString:@"Faces"])
{
return FACES_ID_SPACE;
}
} else if ([inAlbumType isEqualToString:@"Photo Stream"])
{
return PHOTO_STREAM_ID_SPACE;
}
return ALBUMS_ID_SPACE;
}

Expand All @@ -796,21 +844,42 @@ - (BOOL) isLeafAlbumType:(NSString*)inType


//----------------------------------------------------------------------------------------------------------------------
// Returns the standard album of all photos ("Photos") in its plist representation
// Returns an album found in the album list in its plist representation based on a blocks boolean return value.
// Will also return the index where it is to be found as reference.

- (NSDictionary*) allPhotosAlbumInAlbumList:(NSArray*)inAlbumList atIndex:(NSNumber**)outIndex
- (NSUInteger) indexOfAlbumInAlbumList:(NSArray*)inAlbumList passingTest:(SEL)predicateSelector
{
NSUInteger i, count = [inAlbumList count];
for (i = 0; i < count; i++)
{
NSDictionary* albumDict = [inAlbumList objectAtIndex:i];
if ([self isAllPhotosAlbum:albumDict])
// Transform predicate into block (needed by -[indexOfObjectPassingTest]:)
BOOL(^listPredicate)(id, NSUInteger, BOOL *) = ^(id albumDict, NSUInteger idx, BOOL *stop)
{
if ([self performSelector:predicateSelector withObject:albumDict])
{
*outIndex = [NSNumber numberWithUnsignedInteger:i];
return albumDict;
*stop = YES;
return YES;
}
}
return nil;
return NO;
};

return [inAlbumList indexOfObjectPassingTest:listPredicate];
}


//----------------------------------------------------------------------------------------------------------------------
// Returns the index of the all photos album ("Photos") in given album list

- (NSUInteger) indexOfAllPhotosAlbumInAlbumList:(NSArray*)inAlbumList
{
return [self indexOfAlbumInAlbumList:inAlbumList passingTest:@selector(isAllPhotosAlbum:)];
}


//----------------------------------------------------------------------------------------------------------------------
// Returns the index of the flagged album ("Flagged") in given album list

- (NSUInteger) indexOfFlaggedAlbumInAlbumList:(NSArray*)inAlbumList
{
return [self indexOfAlbumInAlbumList:inAlbumList passingTest:@selector(isFlaggedAlbum:)];
}


Expand All @@ -823,15 +892,24 @@ - (NSString*) requestedImageRepresentationType
}


//----------------------------------------------------------------------------------------------------------------------
// Returns whether inNode has id x and belongs to id space y

- (BOOL) isNode:(IMBNode*)inNode withId:(NSUInteger)inId inSpace:(NSString *)inIdSpace
{
NSNumber* nodeId = [NSNumber numberWithUnsignedInt:inId];
NSString* nodeIdentifier = [self identifierForId:nodeId inSpace:inIdSpace];

return [inNode.identifier isEqualToString:nodeIdentifier];
}


//----------------------------------------------------------------------------------------------------------------------
// Returns whether inNode is the events node

- (BOOL) isEventsNode:(IMBNode*)inNode
{
NSNumber* eventsId = [NSNumber numberWithUnsignedInt:EVENTS_NODE_ID];
NSString* eventsIdentifier = [self identifierForId:eventsId inSpace:EVENTS_ID_SPACE];

return [inNode.identifier isEqualToString:eventsIdentifier];
return [self isNode:inNode withId:EVENTS_NODE_ID inSpace:EVENTS_ID_SPACE];
}


Expand All @@ -840,10 +918,16 @@ - (BOOL) isEventsNode:(IMBNode*)inNode

- (BOOL) isFacesNode:(IMBNode*)inNode
{
NSNumber* facesId= [NSNumber numberWithUnsignedInt:FACES_NODE_ID];
NSString* facesIdentifier = [self identifierForId:facesId inSpace:FACES_ID_SPACE];

return [inNode.identifier isEqualToString:facesIdentifier];
return [self isNode:inNode withId:FACES_NODE_ID inSpace:FACES_ID_SPACE];
}


//----------------------------------------------------------------------------------------------------------------------
// Returns whether inNode is the Photo Stream node

- (BOOL) isPhotoStreamNode:(IMBNode*)inNode
{
return [self isNode:inNode withId:PHOTO_STREAM_NODE_ID inSpace:PHOTO_STREAM_ID_SPACE];
}


Expand Down
1 change: 1 addition & 0 deletions IMBNodeViewController.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
NSString* _selectedNodeIdentifier;
NSMutableArray* _expandedNodeIdentifiers;
BOOL _isRestoringState;
NSPoint _nodeOutlineViewSavedVisibleRectOrigin;
IMBParser* _selectedParser;

IBOutlet NSSplitView* ibSplitView;
Expand Down
13 changes: 12 additions & 1 deletion IMBNodeViewController.m
Original file line number Diff line number Diff line change
Expand Up @@ -789,10 +789,16 @@ - (IMBNode*) _nodeAtRow:(NSInteger)inRow
// Called in response to a IMBNodesWillChangeNotification notification. Set a flag that helps us to do the right
// thing in the IMBOutlineView delegate methods. If nodes are currently being replaced, then we will allow any
// changes, because those changes were not initiated by user events...
// And it will allow us to save any state information that might be unintentionally changed through the
// replacements of nodes (remember that the libary controller has a binding with the outline view)

- (void) _nodesWillChange
{

// Since the replacing of nodes in the library controller will lead to side effects
// regarding the current scroll position of the outline view we have to save it here
// for later restauration

_nodeOutlineViewSavedVisibleRectOrigin = [ibNodeOutlineView visibleRect].origin;
}


Expand Down Expand Up @@ -882,6 +888,10 @@ - (void) _nodesDidChange
[self __updatePopupMenu];
[self __syncPopupMenuSelection];

// Restore scroll position of outline view (see _nodesWillChange for further explanation)

[ibNodeOutlineView scrollPoint:_nodeOutlineViewSavedVisibleRectOrigin];

// We are done, now the user is once again in charge...

_isRestoringState = NO;
Expand Down Expand Up @@ -1526,6 +1536,7 @@ - (NSSize) minimumViewSize
- (void) restoreState
{
[self _loadStateFromPreferences];
[self _nodesWillChange];
[self _nodesDidChange];
}

Expand Down
2 changes: 2 additions & 0 deletions IMBTestAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,8 @@ - (CALayer*) imageBrowserBackgroundLayerForController:(IMBObjectViewController*)

CGColorRef color = CGColorCreate(colorSpace, fillComponents);
[backgroundLayer setBackgroundColor:color];
CFRelease(colorSpace);
CFRelease(color);

return backgroundLayer;
}
Expand Down
1 change: 1 addition & 0 deletions IMBTestFacesBackgroundLayer.m
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ CGImageRef createImageWithName(NSString* imageName)

if(imageSource){
returnValue = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
CFRelease(imageSource);
}
}

Expand Down
Loading