#import "NSObject+NSCoding.h"
#import "PithosUtilities.h"
-
@implementation Folder
-@synthesize name, parent, folders, objects, metadata, sharing, contentType;
+@synthesize folderObject, parent, objects, folders, objectsAndFoldersCount;
+@synthesize name, sharing, contentType, lastModifiedString, metadata;
+
+#pragma mark - Object lifecycle
+
+- (id)initWithObject:(StorageObject *)anObject {
+ if ((self = [super init])) {
+ self.folderObject = anObject;
+ self.objects = [NSMutableDictionary dictionary];
+ self.folders = [NSMutableDictionary dictionary];
+ }
+ return self;
+}
+
+- (id)init {
+ StorageObject *anObject = [[[StorageObject alloc] init] autorelease];
+ return [self initWithObject:anObject];
+}
+
++ (id)folderWithObject:(StorageObject *)anObject {
+ return [[[self alloc] initWithObject:anObject] autorelease];
+}
+ (id)folder {
- Folder *folder = [[[self alloc] init] autorelease];
- folder.folders = [[NSMutableDictionary alloc] init];
- folder.objects = [[NSMutableDictionary alloc] init];
- return folder;
+ return [[[self alloc] init] autorelease];
}
-#pragma mark -
-#pragma mark Serialization
+- (NSComparisonResult)compare:(Folder *)aFolder {
+ return [self.name caseInsensitiveCompare:aFolder.name];
+}
-- (id)init {
- if (self = [super init]) {
- self.folders = [[NSMutableDictionary alloc] init];
- self.objects = [[NSMutableDictionary alloc] init];
+#pragma mark - Serialization
+
+- (id)initWithCoder:(NSCoder *)coder {
+ if ((self = [super init])) {
+ [self autoDecode:coder];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[self autoEncodeWithCoder:coder];
- /*
- [coder encodeObject:name forKey:@"name"];
- [coder encodeObject:parent forKey:@"parent"];
- [coder encodeObject:folders forKey:@"folders"];
- [coder encodeObject:objects forKey:@"objects"];
- */
}
-- (id)initWithCoder:(NSCoder *)coder {
- if (self = [super init]) {
- [self autoDecode:coder];
- /*
- name = [[coder decodeObjectForKey:@"name"] retain];
- parent = [[coder decodeObjectForKey:@"parent"] retain];
- folders = [[coder decodeObjectForKey:@"folders"] retain];
- objects = [[coder decodeObjectForKey:@"objects"] retain];
- */
- }
- return self;
+#pragma mark - Memory management
+
+-(void)dealloc {
+ [folderObject release];
+ [parent release];
+ [folders release];
+ [objects release];
+ [sortedContents release];
+ [super dealloc];
+}
+
+#pragma mark - Properties
+
+- (void)setName:(NSString *)aName {
+ self.folderObject.name = aName;
}
+- (NSString *)name {
+ return self.folderObject.name;
+}
+
+- (void)setSharing:(NSString *)aSharing {
+ self.folderObject.sharing = aSharing;
+}
+
+- (NSString *)sharing {
+ return self.folderObject.sharing;
+}
+
+- (void)setContentType:(NSString *)aContentType {
+ self.folderObject.contentType = aContentType;
+}
+
+- (NSString *)contentType {
+ return self.folderObject.contentType;
+}
+
+- (void)setMetadata:(NSMutableDictionary *)aMetadata {
+ self.folderObject.metadata = aMetadata;
+}
+
+- (NSMutableDictionary *)metadata {
+ return self.folderObject.metadata;
+}
+
+- (void)setLastModifiedString:(NSString *)aLastModifiedString {
+ self.folderObject.lastModifiedString = aLastModifiedString;
+}
+
+- (NSString *)lastModifiedString {
+ return self.folderObject.lastModifiedString;
+}
- (void)setObjects:(NSMutableDictionary *)objs {
- if (self.objects != objs) {
- [self.objects release];
-
- NSMutableDictionary *folderedFiles = [[NSMutableDictionary alloc] init];
- NSMutableDictionary *files = [[NSMutableDictionary alloc] init];
- folders = [[NSMutableDictionary alloc] init];
+ if (![objects isEqualToDictionary:objs]) {
+ [objects release];
+ NSMutableDictionary *folderedFiles = [NSMutableDictionary dictionary];
+ NSMutableDictionary *files = [NSMutableDictionary dictionary];
+ self.folders = [[NSMutableDictionary alloc] init];
for (NSString *key in objs) {
StorageObject *object = [objs objectForKey:key];
object.name = [object.name substringToIndex:(object.name.length - 1)];
}
- NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"/" options:NSRegularExpressionCaseInsensitive error:nil];
- NSInteger matches = [regex numberOfMatchesInString:object.name options:0 range:NSMakeRange(0, [object.name length])];
-
- if (matches > 0) {
+ NSRange slashRange = [object.name rangeOfString:@"/"];
+ if (slashRange.location != NSNotFound) {
// build up the folder structure
- NSMutableArray *components = [NSMutableArray arrayWithArray:[object.name componentsSeparatedByString:@"/"]];
- NSString *folderName = [components objectAtIndex:0];
-
- object.name = [components lastObject];
+ NSString *folderName = [object.name substringToIndex:slashRange.location];
+ object.name = [object.name substringFromIndex:(slashRange.location + 1)];
if (objectHasTrailingSlash)
object.name = [object.name stringByAppendingString:@"/"];
- for (int i = [components count] - 2; i > 0; i--) {
- object.name = [NSString stringWithFormat:@"%@/%@", [components objectAtIndex:i], object.name];
- }
-
if (![folderedFiles objectForKey:folderName]) {
- [folderedFiles setObject:[[NSMutableDictionary alloc] init] forKey:folderName];
+ [folderedFiles setObject:[NSMutableDictionary dictionary] forKey:folderName];
}
NSMutableDictionary *folderFiles = [folderedFiles objectForKey:folderName];
[folderFiles setObject:object forKey:object.name];
} else if ([PithosUtilities isContentTypeDirectory:object.contentType]) {
- Folder *folder = [[Folder alloc] init];
+ Folder *folder = [Folder folderWithObject:object];
if (objectHasTrailingSlash)
- folder.name = [NSString stringWithFormat:@"%@/", object.name];
- else
- folder.name = object.name;
+ folder.name = [folder.name stringByAppendingString:@"/"];
folder.parent = self;
- folder.metadata = object.metadata;
- folder.sharing = object.sharing;
- folder.contentType = object.contentType;
[self.folders setObject:folder forKey:folder.name];
- [folder release];
} else {
// put the files in this folder
if (objectHasTrailingSlash)
}
// take the foldered files and recursively build the rest of the folder structure
- NSArray *keys = [folderedFiles allKeys];
- for (int i = 0; i < [keys count]; i++) {
- NSString *folderName = [keys objectAtIndex:i];
- NSMutableDictionary *folderFiles = [folderedFiles objectForKey:folderName];
- Folder *folder = [[Folder alloc] init];
- folder.name = folderName;
- folder.parent = self;
- folder.objects = folderFiles;
+ for (NSString *folderName in [folderedFiles allKeys]) {
+ Folder *folder;
StorageObject *object = [objs objectForKey:folderName];
- if ([PithosUtilities isContentTypeDirectory:object.contentType]) {
- folder.metadata = object.metadata;
- folder.sharing = object.sharing;
- folder.contentType = object.contentType;
+ if (object && [PithosUtilities isContentTypeDirectory:object.contentType]) {
+ folder = [Folder folderWithObject:object];
+ } else {
+ folder = [Folder folder];
+ folder.name = folderName;
+ folder.metadata = [NSMutableDictionary dictionary];
}
+ folder.parent = self;
+ folder.objects = [folderedFiles objectForKey:folderName];
[self.folders setObject:folder forKey:folder.name];
- [folder release];
}
- [folderedFiles release];
- objects = files;
+ objects = [files retain];
+ [sortedContents release];
+ sortedContents = nil;
}
}
- (NSArray *)sortedContents {
- NSMutableArray *contents = [[NSMutableArray alloc] initWithArray:[self.folders allValues]];
-
- [contents addObjectsFromArray:[self.objects allValues]];
- if (!sortedContents || ![sortedContents isEqualToArray:contents]) {
+ if (!sortedContents) {
+ NSMutableArray *contents = [[NSMutableArray alloc] initWithArray:[self.folders allValues]];
+ [contents addObjectsFromArray:[self.objects allValues]];
sortedContents = [[NSArray alloc] initWithArray:[contents sortedArrayUsingSelector:@selector(compare:)]];
}
- [contents release];
return sortedContents;
}
-- (NSComparisonResult)compare:(Folder *)aFolder {
- return [self.name caseInsensitiveCompare:aFolder.name];
+- (NSUInteger)objectsAndFoldersCount {
+ return (self.objects.count + self.folders.count);
+}
+
+#pragma mark - Actions
+
+- (NSArray *)sortedContentsUsingFilter:(NSString *)filter andScope:(NSString *)scope {
+ if (!filter || !filter.length)
+ return self.sortedContents;
+ return [self.sortedContents objectsAtIndexes:
+ [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.sortedContents.count)] indexesPassingTest:^(NSUInteger idx, BOOL *stop) {
+ id item = [self.sortedContents objectAtIndex:idx];
+ if ([scope isEqualToString:@"name"] || [scope isEqualToString:@"all"]) {
+ NSString *itemName = [item name];
+ if (itemName) {
+ NSUInteger nameLocation = [itemName rangeOfString:filter
+ options:NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch].location;
+ if (nameLocation != NSNotFound)
+ return YES;
+ }
+ }
+ if ([scope isEqualToString:@"date"] || [scope isEqualToString:@"all"]) {
+ NSString *itemDate = [item lastModifiedString];
+ if (itemDate) {
+ NSUInteger dateLocation = [itemDate rangeOfString:filter
+ options:NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch].location;
+ if (dateLocation != NSNotFound)
+ return YES;
+ }
+ }
+ if ([scope isEqualToString:@"type"] || [scope isEqualToString:@"all"]) {
+ NSString *itemType = [item contentType];
+ if (itemType) {
+ NSUInteger typeLocation = [itemType rangeOfString:filter
+ options:NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch].location;
+ if (typeLocation != NSNotFound)
+ return YES;
+ }
+ }
+ // Consider searching additional metadata when the scope is all
+ return NO;
+ }]];
+}
+
+- (NSArray *)sortedContentsWithNameThatStartsWith:(NSString *)filter {
+ if (!filter || !filter.length)
+ return self.sortedContents;
+ return [self.sortedContents objectsAtIndexes:
+ [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.sortedContents.count)] indexesPassingTest:^(NSUInteger idx, BOOL *stop) {
+ BOOL hasPrefix = [(NSString *)[[self.sortedContents objectAtIndex:idx] name] hasPrefix:filter];
+ if (hasPrefix)
+ return YES;
+ NSComparisonResult comparisonResult = [(NSString *)[[self.sortedContents objectAtIndex:idx] name] compare:filter];
+ if (comparisonResult == NSOrderedDescending)
+ *stop = YES;
+ return NO;
+ }]];
}
- (NSString *)fullPath {
- NSString *result = self.name;
- if (parent) {
- result = [NSString stringWithFormat:@"%@/%@", [parent fullPath], self.name];
+ if (self.parent) {
+ return [[self.parent fullPath] stringByAppendingFormat:@"/%@", self.name];
+ } else if (self.name) {
+ return self.name;
+ } else {
+ return @"";
}
- if (!result) {
- result = @"";
- }
- return result;
}
--(void)dealloc {
- [name release];
- [parent release];
- [folders release];
- [sharing release];
- [objects release];
+- (void)addFolder:(Folder *)aFolder {
+ [self.folders setObject:aFolder forKey:aFolder.name];
[sortedContents release];
- [contentType release];
- [super dealloc];
+ sortedContents = nil;
+}
+
+- (void)addObject:(StorageObject *)anObject {
+ [self.objects setObject:anObject forKey:anObject.name];
+ [sortedContents release];
+ sortedContents = nil;
+}
+
+- (void)removeFolder:(Folder *)aFolder {
+ if ([self.folders objectForKey:aFolder.name]) {
+ [self.folders removeObjectForKey:aFolder.name];
+ [sortedContents release];
+ sortedContents = nil;
+ }
+}
+
+- (void)removeObject:(StorageObject *)anObject {
+ if ([self.objects objectForKey:anObject.name]) {
+ [self.objects removeObjectForKey:anObject.name];
+ [sortedContents release];
+ sortedContents = nil;
+ }
}
@end