Statistics
| Branch: | Tag: | Revision:

root / Classes / Folder.m @ f474d3f4

History | View | Annotate | Download (10.2 kB)

1
//
2
//  Folder.m
3
//  OpenStack
4
//
5
//  Created by Mike Mayo on 12/7/10.
6
//  The OpenStack project is provided under the Apache 2.0 license.
7
//
8

    
9
#import "Folder.h"
10
#import "StorageObject.h"
11
#import "NSObject+NSCoding.h"
12
#import "PithosUtilities.h"
13

    
14
@implementation Folder
15

    
16
@synthesize folderObject, parent, objects, folders, objectsAndFoldersCount;
17
@synthesize name, sharing, contentType, lastModifiedString, metadata;
18
@synthesize sortedContentsByName, sortedContentsByDate;
19

    
20
#pragma mark - Object lifecycle
21

    
22
- (id)initWithObject:(StorageObject *)anObject {
23
    if ((self = [super init])) {
24
        self.folderObject = anObject;
25
        self.objects = [NSMutableDictionary dictionary];
26
        self.folders = [NSMutableDictionary dictionary];
27
    }
28
    return self;
29
}
30

    
31
- (id)init {
32
    StorageObject *anObject = [[[StorageObject alloc] init] autorelease];
33
    return [self initWithObject:anObject];
34
}
35

    
36
+ (id)folderWithObject:(StorageObject *)anObject {
37
    return [[[self alloc] initWithObject:anObject] autorelease];
38
}
39

    
40
+ (id)folder {
41
    return [[[self alloc] init] autorelease];
42
}
43

    
44
- (NSComparisonResult)compareByName:(id)item {
45
    return [self.name caseInsensitiveCompare:[item name]];
46
}
47

    
48
- (NSComparisonResult)compareByDate:(id)item {
49
    return [self.lastModifiedString caseInsensitiveCompare:[item lastModifiedString]];
50
}
51

    
52
#pragma mark - Serialization
53

    
54
- (id)initWithCoder:(NSCoder *)coder {
55
    if ((self = [super init])) {
56
        [self autoDecode:coder];
57
    }
58
    return self;
59
}
60

    
61
- (void)encodeWithCoder:(NSCoder *)coder {
62
    [self autoEncodeWithCoder:coder];
63
}
64

    
65
#pragma mark - Memory management
66

    
67
-(void)dealloc {
68
    [folderObject release];
69
	[parent release];
70
	[folders release];
71
	[objects release];
72
    [sortedContentsByName release];
73
    [sortedContentsByDate release];
74
	[super dealloc];
75
}
76

    
77
#pragma mark - Properties
78

    
79
- (void)setName:(NSString *)aName {
80
    self.folderObject.name = aName;
81
}
82

    
83
- (NSString *)name {
84
    return self.folderObject.name;
85
}
86

    
87
- (void)setSharing:(NSString *)aSharing {
88
    self.folderObject.sharing = aSharing;
89
}
90

    
91
- (NSString *)sharing {
92
    return self.folderObject.sharing;
93
}
94

    
95
- (void)setContentType:(NSString *)aContentType {
96
    self.folderObject.contentType = aContentType;
97
}
98

    
99
- (NSString *)contentType {
100
    return self.folderObject.contentType;
101
}
102

    
103
- (void)setMetadata:(NSMutableDictionary *)aMetadata {
104
    self.folderObject.metadata = aMetadata;
105
}
106

    
107
- (NSMutableDictionary *)metadata {
108
    return self.folderObject.metadata;
109
}
110

    
111
- (void)setLastModifiedString:(NSString *)aLastModifiedString {
112
    self.folderObject.lastModifiedString = aLastModifiedString;
113
}
114

    
115
- (NSString *)lastModifiedString {
116
    return self.folderObject.lastModifiedString;
117
}
118

    
119
- (void)setObjects:(NSMutableDictionary *)objs {
120
    if (![objects isEqualToDictionary:objs]) {
121
        [objects release];
122
        NSMutableDictionary *folderedFiles = [NSMutableDictionary dictionary];
123
        NSMutableDictionary *files = [NSMutableDictionary dictionary];
124
        self.folders = [[NSMutableDictionary alloc] init];
125

    
126
        for (NSString *key in objs) {
127
            StorageObject *object = [objs objectForKey:key];
128
            BOOL objectHasTrailingSlash = NO;
129
            if ([object.name hasSuffix:@"/"]) {
130
                objectHasTrailingSlash = YES;
131
                object.name = [object.name substringToIndex:(object.name.length - 1)];
132
            }
133

    
134
            NSRange slashRange = [object.name rangeOfString:@"/"];
135
            if (slashRange.location != NSNotFound) {
136
                // build up the folder structure
137
                NSString *folderName = [object.name substringToIndex:slashRange.location];
138
                object.name = [object.name substringFromIndex:(slashRange.location + 1)];
139
                if (objectHasTrailingSlash)
140
                    object.name = [object.name stringByAppendingString:@"/"];
141
                
142
                if (![folderedFiles objectForKey:folderName]) {
143
                    [folderedFiles setObject:[NSMutableDictionary dictionary] forKey:folderName];
144
                }
145
                
146
                NSMutableDictionary *folderFiles = [folderedFiles objectForKey:folderName];
147
                [folderFiles setObject:object forKey:object.name]; 
148
            } else if ([PithosUtilities isContentTypeDirectory:object.contentType]) {
149
                Folder *folder = [Folder folderWithObject:object];
150
                if (objectHasTrailingSlash)
151
                    folder.name = [folder.name stringByAppendingString:@"/"];
152
                folder.parent = self;
153
                [self.folders setObject:folder forKey:folder.name];
154
            } else {
155
                // put the files in this folder 
156
                if (objectHasTrailingSlash)
157
                    object.name = [object.name stringByAppendingString:@"/"];
158
                [files setObject:object forKey:object.name];
159
            }
160
        }
161
        
162
        // take the foldered files and recursively build the rest of the folder structure
163
        for (NSString *folderName in [folderedFiles allKeys]) {
164
            Folder *folder;
165
            StorageObject *object = [objs objectForKey:folderName];
166
            if (object && [PithosUtilities isContentTypeDirectory:object.contentType]) {
167
                folder = [Folder folderWithObject:object];
168
            } else {
169
                folder = [Folder folder];
170
                folder.name = folderName;
171
                folder.metadata = [NSMutableDictionary dictionary];
172
            }
173
            folder.parent = self;
174
            folder.objects = [folderedFiles objectForKey:folderName];
175
            [self.folders setObject:folder forKey:folder.name];
176
        }
177
        
178
        objects = [files retain];
179
        [sortedContentsByName release];
180
        sortedContentsByName = nil;
181
        [sortedContentsByDate release];
182
        sortedContentsByDate = nil;
183
    }
184
}
185

    
186
- (NSArray *)sortedContentsByName {
187
    if (!sortedContentsByName) {
188
        NSMutableArray *contents = [[NSMutableArray alloc] initWithArray:[self.folders allValues]];
189
        [contents addObjectsFromArray:[self.objects allValues]];
190
        sortedContentsByName = [[NSArray alloc] initWithArray:[contents sortedArrayUsingSelector:@selector(compareByName:)]];
191
    }
192
    return sortedContentsByName;
193
}
194

    
195
- (NSArray *)sortedContentsByDate {
196
    if (!sortedContentsByDate) {
197
        NSMutableArray *contents = [[NSMutableArray alloc] initWithArray:[self.folders allValues]];
198
        [contents addObjectsFromArray:[self.objects allValues]];
199
        sortedContentsByDate = [[NSArray alloc] initWithArray:[contents sortedArrayUsingSelector:@selector(compareByDate:)]];
200
    }
201
    return sortedContentsByDate;
202
}
203

    
204
- (NSUInteger)objectsAndFoldersCount {
205
    return (self.objects.count + self.folders.count);
206
}
207

    
208
#pragma mark - Actions
209

    
210
- (NSArray *)sortedContentsUsingFilter:(NSString *)filter scope:(NSString *)scope
211
                              sortType:(NSString *)sortType sortDirection:(NSString *)sortDirection {
212
    NSArray *sortedContents = nil;
213
    if ([sortType isEqualToString:@"date"]) {
214
        sortedContents = self.sortedContentsByDate;
215
    } else {
216
        sortedContents = self.sortedContentsByName;
217
    }
218
    if ([sortDirection isEqualToString:@"Z-A"]) {
219
        sortedContents = [[sortedContents reverseObjectEnumerator] allObjects];
220
    }
221
    if (!filter || !filter.length) {
222
        return sortedContents;
223
    }
224
    return [sortedContents objectsAtIndexes:
225
            [[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sortedContents.count)] indexesPassingTest:^(NSUInteger idx, BOOL *stop) {
226
        id item = [sortedContents objectAtIndex:idx];
227
        if ([scope isEqualToString:@"name"] || [scope isEqualToString:@"all"]) {
228
            NSString *itemName = [item name];
229
            if (itemName) {
230
                NSUInteger nameLocation = [itemName rangeOfString:filter
231
                                                          options:NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch].location;
232
                if (nameLocation != NSNotFound)
233
                    return YES;
234
            }
235
        }
236
        if ([scope isEqualToString:@"date"] || [scope isEqualToString:@"all"]) {
237
            NSString *itemDate = [item lastModifiedString];
238
            if (itemDate) {
239
                NSUInteger dateLocation = [itemDate rangeOfString:filter
240
                                                          options:NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch].location;
241
                if (dateLocation != NSNotFound)
242
                    return YES;
243
            }
244
        }
245
        if ([scope isEqualToString:@"type"] || [scope isEqualToString:@"all"]) {
246
            NSString *itemType = [item contentType];
247
            if (itemType) {
248
                NSUInteger typeLocation = [itemType rangeOfString:filter
249
                                                          options:NSCaseInsensitiveSearch|NSDiacriticInsensitiveSearch].location;
250
                if (typeLocation != NSNotFound)
251
                    return YES;
252
            }
253
        }
254
        // Consider searching additional metadata when the scope is all
255
        return NO;
256
    }]];
257
}
258

    
259
- (NSString *)fullPath {
260
    if (self.parent) {
261
        return [[self.parent fullPath] stringByAppendingFormat:@"/%@", self.name];
262
    } else if (self.name) {
263
        return self.name;
264
    } else {
265
        return @"";
266
    }
267
}
268

    
269
- (void)addFolder:(Folder *)aFolder {
270
    [self.folders setObject:aFolder forKey:aFolder.name];
271
    [sortedContentsByName release];
272
    sortedContentsByName = nil;
273
    [sortedContentsByDate release];
274
    sortedContentsByDate = nil;
275
}
276

    
277
- (void)addObject:(StorageObject *)anObject {
278
    [self.objects setObject:anObject forKey:anObject.name];
279
    [sortedContentsByName release];
280
    sortedContentsByName = nil;
281
    [sortedContentsByDate release];
282
    sortedContentsByDate = nil;
283
}
284

    
285
- (void)removeFolder:(Folder *)aFolder {
286
    if ([self.folders objectForKey:aFolder.name]) {
287
        [self.folders removeObjectForKey:aFolder.name];
288
        [sortedContentsByName release];
289
        sortedContentsByName = nil;
290
        [sortedContentsByDate release];
291
        sortedContentsByDate = nil;
292
    }
293
}
294

    
295
- (void)removeObject:(StorageObject *)anObject {
296
    if ([self.objects objectForKey:anObject.name]) {
297
        [self.objects removeObjectForKey:anObject.name];
298
        [sortedContentsByName release];
299
        sortedContentsByName = nil;
300
        [sortedContentsByDate release];
301
        sortedContentsByDate = nil;
302
    }
303
}
304

    
305
@end