-//
-// ApertureToAnselExportPlugin.h
-// ApertureToAnselExportPlugin
-//
-// Created by Michael Rubinsky on 8/29/09.
-// Copyright __MyCompanyName__ 2009. All rights reserved.
-//
-
+/**
+ * ApertureToAnselExportPlugin.h
+ * ApertureToAnselExportPlugin
+ *
+ * Copyright 2009-2010 The Horde Project (http://www.horde.org)
+ *
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ */
#import <Cocoa/Cocoa.h>
#import <Quartz/Quartz.h>
#endif
{
// The cached API Manager object, as passed to the -initWithAPIManager: method.
- id _apiManager;
-
+ id _apiManager;
+
// The cached Aperture Export Manager object - you should fetch this from the API Manager during -initWithAPIManager:
- NSObject<ApertureExportManager, PROAPIObject> *_exportManager;
-
+ NSObject<ApertureExportManager, PROAPIObject> *_exportManager;
+
// The lock used to protect all access to the ApertureExportProgress structure
NSLock *_progressLock;
-
+
// Top-level objects in the nib are automatically retained - this array
// tracks those, and releases them
NSArray *_topLevelNibObjects;
-
+
// The structure used to pass all progress information back to Aperture
ApertureExportProgress exportProgress;
// TURAnsel objects
TURAnselGallery *_currentGallery;
TURAnsel *_anselController;
-
+
// Outlets to your plug-ins user interface
IBOutlet NSView *settingsView;
IBOutlet NSView *firstView;
IBOutlet NSView *lastView;
-
+
IBOutlet NSComboBox *galleryCombo;
IBOutlet NSTextField *statusLabel;
IBOutlet NSProgressIndicator *spinner;
IBOutlet NSImageView *defaultImageView;
IBOutlet NSButton *mNewGalleryButton;
IBOutlet NSPopUpButton *mServersPopUp;
-
+
// New Server sheet
IBOutlet NSWindow *newServerSheet;
IBOutlet NSTextField *mServerSheetHostURL;
- IBOutlet NSTextField *mServerSheetUsername;
+ IBOutlet NSTextField *mServerSheetUsername;
IBOutlet NSSecureTextField *mServerSheetPassword;
IBOutlet NSTextField *mServerSheetServerNickName;
IBOutlet NSButton *mMakeNewServerDefault;
IBOutlet NSPopUpButton *mAnselVersion;
-
+
// Server list
IBOutlet NSPanel *serverListPanel;
IBOutlet NSTableView *serverTable;
IBOutlet NSButton *closeGalleryView;
IBOutlet IKImageBrowserView *browserView;
NSMutableArray *_browserData;
-
+
// Flags, counters etc...
BOOL cancelExport;
int _currentImageCount;
-
+
BOOL isExporting;
}
-//
-// ApertureToAnselExportPlugin.m
-// ApertureToAnselExportPlugin
-//
-// Created by Michael Rubinsky on 8/29/09.
-// Copyright __MyCompanyName__ 2009. All rights reserved.
-//
-
+/**
+ * ApertureToAnselExportPlugin.m
+ * ApertureToAnselExportPlugin
+ *
+ * Copyright 2009-2010 The Horde Project (http://www.horde.org)
+ *
+ * @license http://opensource.org/licenses/bsd-license.php
+ * @author Michael J. Rubinsky <mrubinsk@horde.org>
+ */
#import "ApertureToAnselExportPlugin.h"
#import "TURAnselKit.h"
#import "NSStringAdditions.h"
if (!_exportManager) {
return nil;
}
-
+
_progressLock = [[NSLock alloc] init];
-
+
// Register Application Defaults
NSMutableDictionary *defaultValues = [NSMutableDictionary dictionary];
[defaultValues setObject: [NSNumber numberWithInt: 2]
- forKey: TURAnselExportSize];
-
+ forKey: TURAnselExportSize];
+
[defaultValues setObject: [[NSArray alloc] init] forKey: TURAnselServersKey];
-
+
[defaultValues setObject: [[NSDictionary alloc] init]
forKey: TURAnselDefaultServerKey];
-
+
NSUserDefaults *userPrefs = [NSUserDefaults standardUserDefaults];
[userPrefs registerDefaults: defaultValues];
[self setStatusText: @"Not Connected" withColor: [NSColor redColor]];
[spinner stopAnimation: self];
-
+
// See if we have any configured servers (need a mutable array, hence the extra step here)
_anselServers = [[NSMutableArray alloc] initWithArray: [userPrefs objectForKey:TURAnselServersKey]];
-
+
// Wait until Aperture's export window is fully loaded before attempting a sheet
[[NSNotificationCenter defaultCenter] addObserver: self
selector: @selector(exportWindowDidBecomeKey:)
- name: NSWindowDidBecomeKeyNotification
+ name: NSWindowDidBecomeKeyNotification
object :nil];
-
- // Holds gallery's images info for the gallery preview
+
+ // Holds gallery's images info for the gallery preview
_browserData = [[NSMutableArray alloc] init];
-
+
[self lockProgress];
exportProgress.currentValue = 0;
exportProgress.totalValue = 0;
NSLog(@"ApertureToAnselExportPlugin: dealloc called");
[_anselServers release];
_anselServers = nil;
-
+
[_anselController setDelegate:nil];
[_anselController release];
_anselController = nil;
-
+
[_browserData release];
_browserData = nil;
-
+
// Release the top-level objects from the nib.
[_topLevelNibObjects makeObjectsPerformSelector:@selector(release)];
[_topLevelNibObjects release];
-
+
[_progressLock release];
_progressLock = nil;
-
+
[_exportManager release];
_exportManager = nil;
-
+
[super dealloc];
}
}
[myNib release];
}
-
+
return settingsView;
}
- (BOOL)allowsOnlyPlugInPresets
{
- return NO;
+ return NO;
}
- (BOOL)allowsMasterExport
{
- return NO;
+ return NO;
}
- (BOOL)allowsVersionExport
{
- return YES;
+ return YES;
}
- (BOOL)wantsFileNamingControls
{
- return NO;
+ return NO;
}
- (void)exportManagerExportTypeDidChange
#pragma mark Export Process Methods
- (void)exportManagerShouldBeginExport
-{
+{
NSLog(@"exportManagerShouldBeginExport: %@", _currentGallery);
if (_currentGallery == nil) {
NSLog(@"No gallery selected.");
[_exportManager shouldBeginExport];
}
-- (void)exportManagerWillBeginExportToPath:(NSString *)path
+- (void)exportManagerWillBeginExportToPath:(NSString *)path
{
// noop
}
index + 1, [_exportManager imageCount]] retain];
[self unlockProgress];
- NSString *base64ImageData = [NSString base64StringFromData: imageData
+ NSString *base64ImageData = [NSString base64StringFromData: imageData
length: [imageData length]];
NSDictionary *properties = [_exportManager propertiesWithoutThumbnailForImageAtIndex: index];
NSArray *keys = [[NSArray alloc] initWithObjects:
fileType = @"image/png";
} else if ([format isEqual: [NSNumber numberWithInt: kApertureImageFormatTIFF8]] ||
[format isEqual: [NSNumber numberWithInt: kApertureImageFormatTIFF16]]) {
-
+
// Ansel can handle converting the tiff - it is obviously unable to display the original TIFF file.
fileType = @"image/tiff";
} else {
}
NSLog(@"Image Type: %@", fileType);
-
+
NSArray *values = [[NSArray alloc] initWithObjects:
path,
[properties objectForKey: kExportKeyVersionName],
NSDictionary *imageDataDict = [[NSDictionary alloc] initWithObjects:values
forKeys:keys];
NSDictionary *params = [[NSDictionary alloc] initWithObjectsAndKeys:
- imageDataDict, @"data",
+ imageDataDict, @"data",
[NSNumber numberWithBool:NO], @"default",
nil];
-
+
//Start upload with current gallery.
NSLog(@"Uploading photo %d out of %d", index, [_exportManager imageCount]);
-
+
// Make sure we are around for all callbacks to return even if Aperture cancelled.
[self retain];
[_currentGallery uploadImageObject: params];
[imageDataDict release];
[params release];
-
+
// Returning NO informs Aperture that the plugin is handling the export,
// and NOT Aperture.
- return NO;
+ return NO;
}
// Basically just a success callback
// You must call [_exportManager shouldFinishExport] before Aperture will put away the progress window and complete the export.
// NOTE: You should assume that your plug-in will be deallocated immediately following this call. Be sure you have cleaned up
// any callbacks or running threads before calling.
- [[NSNotificationCenter defaultCenter] removeObserver: self
+ [[NSNotificationCenter defaultCenter] removeObserver: self
name: @"NSPopUpButtonWillPopUpNotification"
object: nil];
-
+
[_exportManager shouldFinishExport];
}
// You must call [_exportManager shouldCancelExport] here or elsewhere before Aperture will cancel the export process
// NOTE: You should assume that your plug-in will be deallocated immediately following this call. Be sure you have cleaned up
// any callbacks or running threads before calling.
- [[NSNotificationCenter defaultCenter] removeObserver: self
+ [[NSNotificationCenter defaultCenter] removeObserver: self
name: @"NSPopUpButtonWillPopUpNotification"
object: nil];
[_anselController cancel];
}
- (void)lockProgress
-{
+{
if (!_progressLock) {
_progressLock = [[NSLock alloc] init];
}
// The ansel controller is initialized, populate the gallery data
// and update the UI.
- (void)TURAnselDidInitialize
-{
+{
NSLog(@"TURAnselDidInitialize");
// Release now that the callback has completed.
[self release];
{
NSLog(@"method: %@", method);
NSLog(@"results: %@", results);
-
+
}
//@TODO - need to add a flag to indicate if we have a UI or not
// Stop the spinner
[spinner stopAnimation: self];
[mServersPopUp setEnabled: true];
-
+
NSAlert *alert;
// For some reason, this method doesn't pick up our userInfo dictionary...
if ([[error userInfo] valueForKey:@"NSLocalizedDescriptionKey"] == nil) {
[alert setInformativeText: [[error userInfo] valueForKey: @"NSLocalizedRecoverySuggestionErrorKey"]];
}
}
-
+
[alert beginSheetModalForWindow:[self window]
modalDelegate:nil
didEndSelector:nil
#pragma mark -
#pragma mark comboBoxDelegate
- (void)comboBoxSelectionDidChange:(NSNotification *)notification
-{
+{
[spinner startAnimation: self];
[self setStatusText: @"Loading gallery data..."];
int row = [galleryCombo indexOfSelectedItem];
[_currentGallery autorelease];
_currentGallery = [[_anselController getGalleryByIndex:row] retain];
[_currentGallery setDelegate: self];
-
+
// Obtain and properly size the image for screen
NSImage *theImage = [[NSImage alloc] initWithContentsOfURL: [_currentGallery galleryKeyImageURL]];
NSSize imageSize;
-
+
// [NSImage bestRepresentationForDevice] is deprecated in 10.6, use bestRepresentationForRect:context:hints: instead if
// we are compiling for a TARGET of 10.6
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_5
#endif
[theImage setScalesWhenResized:YES];
[theImage setSize:imageSize];
-
+
// Show it
[defaultImageView setImage: theImage];
-
+
[theImage release];
[self canExport];
[viewGallery setEnabled: YES];
[[NSNotificationCenter defaultCenter] removeObserver: self
name: NSWindowDidBecomeKeyNotification
object: nil];
-
+
[self updateServersPopupMenu];
-
+
if ([_anselServers count] == 0) {
[self showNewServerSheet];
} else {
if ([defaultServer count]) {
_currentServer = [defaultServer retain];
int itemCount = [mServersPopUp numberOfItems];
-
+
// C99 mode is off by default in Apple's gcc.
int i;
for (i = 0; i < itemCount; i++) {
break;
}
}
-
+
[self doConnect];
}
}
[newServerSheet orderOut: nil];
_currentServer = [newServer retain];
[self doConnect];
-
+
// Save it to the userdefaults
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
- [prefs setObject:_anselServers forKey:TURAnselServersKey];
-
+ [prefs setObject:_anselServers forKey:TURAnselServersKey];
+
int defaultState = [mMakeNewServerDefault state];
if (defaultState == NSOnState) {
[prefs setObject: _currentServer forKey: TURAnselDefaultServerKey];
}
-
+
[prefs synchronize];
[self updateServersPopupMenu];
[newServer release];
[self setStatusText: @"Connected" withColor: [NSColor greenColor]];
return;
}
-
+
for (NSDictionary *image in images) {
// The CF Web Services library can return NSNull objects for values that
// were returned as empty or null, so we need to check for that.
- // (Even if caption is nil, caption.length will still be zero, so we
+ // (Even if caption is nil, caption.length will still be zero, so we
// don't need a seperate case for that).
NSLog(@"Image: %@", image);
NSString *caption = [image objectForKey:@"caption"];
if (caption == (NSString *)[NSNull null] || [caption length] == 0) {
caption = [image objectForKey:@"name"];
}
-
+
NSDate *theDate = [NSDate dateWithTimeIntervalSince1970: [[image objectForKey:@"original_date"] doubleValue]];
AnselGalleryViewItem *item = [[AnselGalleryViewItem alloc] initWithURL: [NSURL URLWithString: [image objectForKey:@"url"]]
withTitle: caption
[_browserData addObject: item];
[item release];
}
-
+
[NSApp beginSheet: mviewGallerySheet
modalForWindow: [self window]
modalDelegate: nil
didEndSelector: nil
contextInfo: nil];
-
+
[spinner stopAnimation: self];
[self setStatusText: @"Connected" withColor: [NSColor greenColor]];
-
+
[browserView reloadData];
-
+
}
- (IBAction) closeGalleryView: (id)sender
- (IBAction)removeServer: (id)sender
{
NSTableColumn *theCol = [serverTable tableColumnWithIdentifier:@"nickname"];
-
- // We are deleting the entry for the currently selected server - make sure
+
+ // We are deleting the entry for the currently selected server - make sure
// we disconnect.
if ([_currentServer objectForKey:TURAnselServerNickKey] == [[theCol dataCell] stringValue]) {
[self disconnect];
}
-
- NSUserDefaults *userPrefs = [NSUserDefaults standardUserDefaults];
-
+
+ NSUserDefaults *userPrefs = [NSUserDefaults standardUserDefaults];
+
// See if the removed server is the current default.
if ([[userPrefs objectForKey:TURAnselDefaultServerKey] objectForKey: TURAnselServerNickKey] == [[theCol dataCell] stringValue]) {
[userPrefs setObject: nil forKey:TURAnselDefaultServerKey];
}
-
+
// Remove it from the servers dictionary
[_anselServers removeObjectAtIndex: [serverTable selectedRow]];
[userPrefs setObject:_anselServers forKey:TURAnselServersKey];
-
+
[userPrefs synchronize];
[serverTable reloadData];
[self updateServersPopupMenu];
NSLog(@"showNewGallery:");
TURAnselGalleryPanelController *newGalleryController;
//NSString *albumName;
-
+
// Make sure we're not doing this for nothing
if ([_anselController state] == TURAnselStateConnected) {
-
+
//albumName = [mExportMgr albumNameAtIndex: 0];
newGalleryController = [[TURAnselGalleryPanelController alloc] initWithController: _anselController];
[newGalleryController setDelegate: self];
[galleryCombo setEnabled: YES];
//} else {
if (1 == 2) {
-
-
+
+
[mNewGalleryButton setEnabled: NO];
[galleryCombo setEnabled: NO];
[viewGallery setEnabled: NO];
[menuItem setRepresentedObject: server];
[[mServersPopUp menu] addItem: menuItem];
}
-
+
// add separator
[[mServersPopUp menu] addItem:[NSMenuItem separatorItem]];
-
+
// add Add Gallery... and Edit List... options
[mServersPopUp addItemWithTitle:@"Add Server..."];
[mServersPopUp addItemWithTitle:@"Edit Server List..."];
-
+
// fix selection
[mServersPopUp selectItemAtIndex:0];
}
modalDelegate: nil
didEndSelector: nil
contextInfo: nil];
-
+
// Make sure these are cleared.
[mServerSheetHostURL setStringValue: @""];
[mServerSheetUsername setStringValue: @""];
[_anselController autorelease];
_anselController = [[TURAnsel alloc] initWithConnectionParameters:p];
[_anselController setDelegate:self];
-
+
// Set up the galleryCombo
[galleryCombo setDataSource:_anselController];
[galleryCombo setDelegate:self];
[spinner startAnimation:self];
-
+
// Detach to a new thread and do the actual login/retrieval of gallery list
[NSApplication detachDrawingThread: @selector(connect)
- toTarget: self
+ toTarget: self
withObject: nil];
[p release];
[_anselController setDelegate: nil];
[_anselController release];
_anselController = nil;
-
+
[self setStatusText:@"Not logged in" withColor: [NSColor redColor]];
}
#pragma mark -
#pragma mark IKImageBrowserView Datasource methods
- (NSUInteger)numberOfItemsInImageBrowser:(IKImageBrowserView *) aBrowser
-{
+{
return [_browserData count];
}
{
NSArray *apiparams;
NSArray *order;
-
+
if ([[self valueForKey: @"version"] intValue] == 2) {
apiparams = [NSArray arrayWithObjects: params, nil];
order = [NSArray arrayWithObjects: kTURAnselAPIParamGalleryParams, nil];
apiparams = [NSArray arrayWithObjects: @"ansel", params, nil];
order = [NSArray arrayWithObjects: kTURAnselAPIParamScope, kTURAnselAPIParamGalleryParams, nil];
}
-
+
NSDictionary *response = [self callRPCMethod: @"images.createGallery"
withParams: apiparams
withOrder: order];
NSLog(@"Results adding credentials to request: %d", success);
if (!success) {
NSLog(@"Unable to authenticate");
-
if ([[self delegate] respondsToSelector: @selector(TURAnselHadError:)]) {
NSError *error = [NSError errorWithDomain:@"TURAnsel"
code: 1
userInfo:[NSDictionary dictionaryWithObjectsAndKeys: @"Authentication failure.", @"message", nil]];
-
[[self delegate] TURAnselHadError: error];
}
return nil;
-
} else {
// Build a new invocation
[self setState:TURAnselStateWaiting];
[[self delegate] TURAnselHadError: error];
}
[result autorelease];
- return nil;
+ return nil;
}
CFHTTPMessageRef response = (CFHTTPMessageRef)[result objectForKey:(id)kWSHTTPResponseMessage];
int resStatusCode = CFHTTPMessageGetResponseStatusCode(response);
NSLog(@"ResponseCode: %d", resStatusCode);
[self setState:TURAnselStateConnected];
+
return [result autorelease];
}
}
-
NSLog(@"No authentication information present.");
- return nil;
+ return nil;
}
#pragma mark -
#pragma mark Setters/Getters
-// Fetch a gallery by id
+/**
+ * Fetch a gallery by it's id.
+ *
+ * @param NSString galleryId The gallery's id.
+ *
+ * @return TURAnselGallery Then gallery object.
+ */
- (TURAnselGallery *)getGalleryById: (NSString *)galleryId
{
for (TURAnselGallery *g in galleryList) {
/**
* Return the gallery at the specified position in the internal storage array.
* Needed for when we are using this class as a datasource for a UI element.
+ *
+ * @param NSInteger index The index into the storage array.
+ *
+ * @return TURAnselGallery The galley obejct located at the specified index.
*/
- (TURAnselGallery *)getGalleryByIndex: (NSInteger)index
{
{
return [galleryList count];
}
-
- (id)comboBox:(NSComboBox *)aComboBox
objectValueForItemAtIndex:(NSInteger)index
{
{
state = newstate;
}
-
- (id)delegate {
return delegate;
}
-
- (void)setDelegate:(id)newDelegate {
delegate = newDelegate;
}
{
NSArray *params;
NSArray *order;
-
+
if ([[self valueForKey: @"version"] intValue] == 2) {
- params = [[NSArray alloc] initWithObjects: [NSDictionary dictionaryWithObjectsAndKeys:
- [NSNumber numberWithInt: PERMS_EDIT], @"perm",
- [self valueForKey:@"username"], @"filter",
- nil] ,nil];
+ params = [NSArray arrayWithObjects: [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt: PERMS_EDIT], @"perm",
+ [self valueForKey:@"username"], @"filter",
+ nil],
+ nil];
order = [NSArray arrayWithObjects: kTURAnselAPIParamSingleParameter, nil];
} else {
// Assume it's version 1.x
- params = [[NSArray alloc] initWithObjects:
+ params = [NSArray arrayWithObjects:
@"ansel", // Scope
[NSNumber numberWithInt: PERMS_EDIT], // Perms
@"", // No parent
[NSNumber numberWithBool:YES], // allLevels
[NSNumber numberWithInt: 0], // Offset
[NSNumber numberWithInt: 0], // Count
- [self valueForKey:@"username"], nil]; // Restrict to user (This should be an option eventually).
+ [self valueForKey:@"username"], nil]; // Restrict to user.
order = [NSArray arrayWithObjects: kTURAnselAPIParamScope, kTURAnselAPIParamPerms,
kTURAnselAPIParamParent, kTURAnselAPIParamAllLevels,
kTURAnselAPIParamOffset, kTURAnselAPIParamCount,
kTURAnselAPIParamUserOnly, nil];
}
-
-
NSDictionary *results = [self callRPCMethod: @"images.listGalleries"
withParams: params
withOrder: order];
-
if (results) {
NSDictionary *galleries = [results objectForKey: (id)kWSMethodInvocationResult];
for (NSString *gal in galleries) {
}
}
-
- [params release];
}
@end