Improved refresh mechanism.
authorMiltiadis Vasilakis <mvasilak@gmail.com>
Sun, 14 Aug 2011 11:38:37 +0000 (14:38 +0300)
committerMiltiadis Vasilakis <mvasilak@gmail.com>
Sun, 14 Aug 2011 11:38:37 +0000 (14:38 +0300)
Other minor fixes and changes.

pithos-macos/PithosAccountNode.h
pithos-macos/PithosAccountNode.m
pithos-macos/PithosBrowserController.m
pithos-macos/PithosContainerNode.h
pithos-macos/PithosContainerNode.m
pithos-macos/PithosNode.h
pithos-macos/PithosNode.m
pithos-macos/PithosObjectNode.h
pithos-macos/PithosObjectNode.m
pithos-macos/PithosSubdirNode.h
pithos-macos/PithosSubdirNode.m

index cfd6541..7700332 100644 (file)
 // or implied, of GRNET S.A.
 
 #import "PithosNode.h"
+@class ASIPithosAccountRequest;
 
 @interface PithosAccountNode : PithosNode {
     NSMutableArray *containers;
-    
-    BOOL refreshing;
+    ASIPithosAccountRequest *accountRequest;
 }
 
-@end
+@end
\ No newline at end of file
index 973d7a1..168bd0a 100644 (file)
 #pragma mark -
 #pragma mark Object Lifecycle
 
-- (id)init {
-    if ((self = [super init])) {
-        refreshing = NO;
-    }
-    return self;
-}
-
 - (void)dealloc {
+    [accountRequest clearDelegatesAndCancel];
+    [accountRequest release];
     [containers release];
     [super dealloc];
 }
@@ -61,7 +56,7 @@
 #pragma mark -
 #pragma mark ASIHTTPRequestDelegate
 
-- (void)requestFinished:(ASIPithosAccountRequest *)accountRequest {
+- (void)requestFinished:(ASIHTTPRequest *)request {
     NSLog(@"URL: %@", [accountRequest url]);
     NSLog(@"cached: %d", [accountRequest didUseCachedResponse]);
     
         if (!accountRequest.didUseCachedResponse || ([containers count] != [someContainers count]) || !children) {
             // Save new children
             NSLog(@"using newChildren");
-            NSMutableArray *newChildren = [NSMutableArray array];
+            newChildren = [NSMutableArray array];
             for (ASIPithosContainer *container in containers) {
                 PithosContainerNode *node = [[[PithosContainerNode alloc] initWithPithosContainer:container] autorelease];
                 if (children) {
                     NSUInteger oldIndex = [children indexOfObject:node];
-                    if (oldIndex != NSNotFound)
+                    if (oldIndex != NSNotFound) {
                         // Use the same pointer value, if possible
                         node = [children objectAtIndex:oldIndex];
+                        node.pithosContainer = container;
+                    }
                 }
                 [newChildren addObject:node];
             }
-            [children release];
-            children = [newChildren retain];
         }
-        // Else cache was used and all results were fetched during this request, so previousChildren can be reused
+        // Else cache was used and all results were fetched during this request, so existing children can be reused
+        [accountRequest release];
+        accountRequest = nil;
         [containers release];
         containers = nil;
         // XXX sort children based on preferences
-        refreshing = NO;
+        @synchronized(self) {
+            freshness = PithosNodeStateRefreshFinished;
+        }
         // Notify observers that children are updated
         [[NSNotificationCenter defaultCenter] postNotificationName:@"PithosAccountNodeChildrenUpdated" object:self];
     } else {
+        [accountRequest release];
         // Do an additional request to fetch more objects
-        ASIPithosAccountRequest *newAccountRequest = [ASIPithosAccountRequest listContainersRequestWithLimit:0 
-                                                                                                      marker:[[someContainers lastObject] name] 
-                                                                                                      shared:NO 
-                                                                                                       until:nil];
-        newAccountRequest.delegate = self;
-        newAccountRequest.downloadCache = [ASIDownloadCache sharedCache];
-        [newAccountRequest startAsynchronous];
+        accountRequest = [[ASIPithosAccountRequest listContainersRequestWithLimit:0 
+                                                                           marker:[[someContainers lastObject] name] 
+                                                                           shared:NO 
+                                                                            until:nil] retain];
+        accountRequest.delegate = self;
+        accountRequest.downloadCache = [ASIDownloadCache sharedCache];
+        [accountRequest startAsynchronous];
     }
 }
 
-- (void)requestFailed:(ASIPithosAccountRequest *)accountRequest {
+- (void)requestFailed:(ASIHTTPRequest *)request {
     // XXX do something on error, cleanup
     NSLog(@"error:%@", [accountRequest error]);
+    [newChildren release];
+    newChildren = nil;
+    [accountRequest release];
+    accountRequest = nil;
     [containers release];
     containers = nil;
-    childrenDirty = YES;
-    refreshing = NO;
+    @synchronized(self) {
+        freshness = PithosNodeStateRefreshNeeded;
+    }
 }
 
 #pragma mark -
 }
 
 - (NSArray *)children {
-    if (childrenDirty) {
-        @synchronized (self) {
-            if (!refreshing) {
-                refreshing = YES;
-                childrenDirty = NO;
-                ASIPithosAccountRequest *accountRequest = [ASIPithosAccountRequest listContainersRequestWithLimit:0 
-                                                                                                           marker:nil 
-                                                                                                           shared:NO 
-                                                                                                            until:nil];
+    @synchronized(self) {
+        switch (freshness) {
+            case PithosNodeStateFresh:
+                break;
+            case PithosNodeStateRefreshNeeded:
+                freshness = PithosNodeStateRefreshing;
+                accountRequest = [[ASIPithosAccountRequest listContainersRequestWithLimit:0 
+                                                                                   marker:nil 
+                                                                                   shared:NO 
+                                                                                    until:nil] retain];
                 accountRequest.delegate = self;
                 accountRequest.downloadCache = [ASIDownloadCache sharedCache];
                 [accountRequest startAsynchronous];
-            }
+                break;
+            case PithosNodeStateRefreshing:
+                break;
+            case PithosNodeStateRefreshFinished:
+                if (newChildren) {
+                    [children release];
+                    children = newChildren;
+                    newChildren = nil;
+                }
+                freshness = PithosNodeStateFresh;
+            default:
+                break;
         }
+        return children;
     }
-    return children;
 }
 
 - (NSString *)displayName {
index 6720a92..d76e31f 100644 (file)
 #pragma Observers
 
 - (void)pithosNodeChildrenUpdated:(NSNotification *)notification {
-    if ([[browser parentForItemsInColumn:[browser lastColumn]] isEqualTo:[notification object]]) 
-        [browser reloadColumn:[browser lastColumn]];
+    PithosNode *node = (PithosNode *)[notification object];
+    NSInteger lastColumn = [browser lastColumn];
+    for (NSInteger column = lastColumn; column >= 0; column--) {
+        if ([[browser parentForItemsInColumn:column] isEqualTo:node]) {
+            [browser reloadColumn:column];
+            if ((column == lastColumn - 1) && ([[browser parentForItemsInColumn:lastColumn] isLeafItem])) {
+                // This reloads the preview column
+                [browser setLastColumn:column];
+                [browser addColumn];
+            }
+            return;
+        }
+    }
 }
 
 #pragma mark -
 #pragma Actions
 
 - (IBAction)refresh:(id)sender {
-    [[browser parentForItemsInColumn:[browser lastColumn]] invalidateChildren];
-    [browser reloadColumn:[browser lastColumn]];
+    for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
+        [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];
+    }
+    [browser validateVisibleColumns];
 }
 
 #pragma mark -
 //    return suggestedWidth;
 //}
 
+- (BOOL)browser:(NSBrowser *)sender isColumnValid:(NSInteger)column {
+    return NO;
+}
+
 #pragma mark -
 #pragma NSSplitViewDelegate
 
 - (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
-    return 100;
+    return 120;
 }
 
 - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
-    return 260;
+    return 220;
 }
 
 #pragma mark -
index a3591b8..ccc88f6 100644 (file)
 // or implied, of GRNET S.A.
 
 #import "PithosNode.h"
-#import "ASIPithosContainer.h"
+@class ASIPithosContainer;
+@class ASIPithosContainerRequest;
 
 @interface PithosContainerNode : PithosNode {
     ASIPithosContainer *pithosContainer;
     
     NSMutableArray *objects;
-    
-    BOOL refreshing;
-    
+    ASIPithosContainerRequest *containerRequest;
     NSString *prefix;
-    
     NSString *childrenUpdatedNotificationName;
 }
 
@@ -55,4 +53,6 @@
 - (id)initWithContainerName:(NSString *)aContainerName;
 - (id)initWithContainerName:(NSString *)aContainerName icon:(NSImage *)anIcon;
 
-@end
+@property(retain) ASIPithosContainer *pithosContainer;
+
+@end
\ No newline at end of file
index 989ca1a..8e1679c 100644 (file)
 #import "PithosObjectNode.h"
 #import "PithosSubdirNode.h"
 #import "ASIPithosContainerRequest.h"
+#import "ASIPithosContainer.h"
 #import "ASIPithosObject.h"
 #import "ASIDownloadCache.h"
 
 static NSImage *sharedIcon = nil;
 
 @implementation PithosContainerNode
+@synthesize pithosContainer;
 
 + (void)initialize {
        if (self == [PithosContainerNode class])
@@ -57,7 +59,6 @@ static NSImage *sharedIcon = nil;
 - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer icon:(NSImage *)anIcon {
     if ((self = [super init])) {
         pithosContainer = [aPithosContainer retain];
-        refreshing = NO;
         prefix = nil;
         icon = [anIcon retain];
         childrenUpdatedNotificationName = @"PithosContainerNodeChildrenUpdated";
@@ -80,6 +81,8 @@ static NSImage *sharedIcon = nil;
 }
 
 - (void)dealloc {
+    [containerRequest clearDelegatesAndCancel];
+    [containerRequest release];
     [childrenUpdatedNotificationName release];
     [prefix release];
     [objects release];
@@ -90,7 +93,7 @@ static NSImage *sharedIcon = nil;
 #pragma mark -
 #pragma mark ASIHTTPRequestDelegate
 
-- (void)requestFinished:(ASIPithosContainerRequest *)containerRequest {
+- (void)requestFinished:(ASIHTTPRequest *)request {
     NSLog(@"URL: %@", [containerRequest url]);
     NSLog(@"cached: %d", [containerRequest didUseCachedResponse]);
 
@@ -104,62 +107,78 @@ static NSImage *sharedIcon = nil;
         if (!containerRequest.didUseCachedResponse || ([objects count] != [someObjects count]) || !children) {
             // Save new children
             NSLog(@"using newChildren");
-            NSMutableArray *newChildren = [NSMutableArray array];
+            newChildren = [[NSMutableArray alloc] init];
             for (ASIPithosObject *object in objects) {
                 if (object.subdir) {
                     PithosSubdirNode *node = [[[PithosSubdirNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
                     if (children) {
                         NSUInteger oldIndex = [children indexOfObject:node];
-                        if (oldIndex != NSNotFound)
+                        if (oldIndex != NSNotFound) {
                             // Use the same pointer value, if possible
                             node = [children objectAtIndex:oldIndex];
+                            node.pithosContainer = pithosContainer;
+                            node.pithosObject = object;
+                        }
                     }
-                    [newChildren addObject:node];                
-                } else {
+                    [newChildren addObject:node];
+                } else if (([self class] != [PithosSubdirNode class]) || (![((PithosSubdirNode *)self).pithosObject.name isEqualToString:object.name])) {
+                    // XXX the if above removes false objects due to trailing slash
+                    // XXX this will change in the server, but it is fixed in the client for now
                     PithosObjectNode *node = [[[PithosObjectNode alloc] initWithPithosContainer:pithosContainer pithosObject:object] autorelease];
                     if (children) {
                         NSUInteger oldIndex = [children indexOfObject:node];
-                        if (oldIndex != NSNotFound)
+                        if (oldIndex != NSNotFound) {
                             // Use the same pointer value, if possible
                             node = [children objectAtIndex:oldIndex];
+                            node.pithosContainer = pithosContainer;
+                            node.pithosObject = object;
+                        }
                     }
                     [newChildren addObject:node];                                
                 }
             }
-            [children release];
-            children = [newChildren retain];
         }
-        // Else cache was used and all results were fetched during this request, so previousChildren can be reused
+        // Else cache was used and all results were fetched during this request, so existing children can be reused
+        [containerRequest release];
+        containerRequest = nil;
         [objects release];
         objects = nil;
-        // XXX sort then based on preferences
-        refreshing = NO;
+        // XXX sort children based on preferences
+        @synchronized(self) {
+            freshness = PithosNodeStateRefreshFinished;
+        }
         // Notify observers that children are updated
         [[NSNotificationCenter defaultCenter] postNotificationName:childrenUpdatedNotificationName object:self];
     } else {
+        [containerRequest release];
         // Do an additional request to fetch more objects
-        ASIPithosContainerRequest *newContainerRequest = [ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
-                                                                                                                  limit:0 
-                                                                                                                 marker:[[someObjects lastObject] name] 
-                                                                                                                 prefix:prefix 
-                                                                                                              delimiter:@"/" 
-                                                                                                                   path:nil 
-                                                                                                                   meta:nil 
-                                                                                                                 shared:NO 
-                                                                                                                  until:nil];
-        newContainerRequest.delegate = self;
-        newContainerRequest.downloadCache = [ASIDownloadCache sharedCache];
-        [newContainerRequest startAsynchronous];
+        containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
+                                                                                     limit:0 
+                                                                                    marker:[[someObjects lastObject] name] 
+                                                                                    prefix:prefix 
+                                                                                 delimiter:@"/" 
+                                                                                      path:nil 
+                                                                                      meta:nil 
+                                                                                    shared:NO 
+                                                                                     until:nil] retain];
+        containerRequest.delegate = self;
+        containerRequest.downloadCache = [ASIDownloadCache sharedCache];
+        [containerRequest startAsynchronous];
     }
 }
 
-- (void)requestFailed:(ASIPithosContainerRequest *)containerRequest {
+- (void)requestFailed:(ASIHTTPRequest *)request {
     // XXX do something on error, cleanup
     NSLog(@"error:%@", [containerRequest error]);
+    [newChildren release];
+    newChildren = nil;
+    [containerRequest release];
+    containerRequest = nil;
     [objects release];
     objects = nil;
-    childrenDirty = YES;
-    refreshing = NO;
+    @synchronized(self) {
+        freshness = PithosNodeStateRefreshNeeded;
+    }
 }
 
 #pragma mark -
@@ -172,27 +191,39 @@ static NSImage *sharedIcon = nil;
 }
 
 - (NSArray *)children {
-    if (childrenDirty) {
-        @synchronized (self) {
-            if (!refreshing) {
-                refreshing = YES;
-                childrenDirty = NO;
-                ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
-                                                                                                                       limit:0 
-                                                                                                                      marker:nil 
-                                                                                                                      prefix:prefix 
-                                                                                                                   delimiter:@"/" 
-                                                                                                                        path:nil 
-                                                                                                                        meta:nil 
-                                                                                                                      shared:NO 
-                                                                                                                       until:nil];
+    @synchronized(self) {
+        switch (freshness) {
+            case PithosNodeStateFresh:
+                break;
+            case PithosNodeStateRefreshNeeded:
+                freshness = PithosNodeStateRefreshing;
+                containerRequest = [[ASIPithosContainerRequest listObjectsRequestWithContainerName:pithosContainer.name 
+                                                                                             limit:0 
+                                                                                            marker:nil 
+                                                                                            prefix:prefix 
+                                                                                         delimiter:@"/" 
+                                                                                              path:nil 
+                                                                                              meta:nil 
+                                                                                            shared:NO 
+                                                                                             until:nil] retain];
                 containerRequest.delegate = self;
                 containerRequest.downloadCache = [ASIDownloadCache sharedCache];
                 [containerRequest startAsynchronous];
-            }
+                break;
+            case PithosNodeStateRefreshing:
+                break;
+            case PithosNodeStateRefreshFinished:
+                if (newChildren) {
+                    [children release];
+                    children = newChildren;
+                    newChildren = nil;
+                }
+                freshness = PithosNodeStateFresh;
+            default:
+                break;
         }
+        return children;
     }
-    return children;
 }
 
 - (NSString *)displayName {
index 8889561..089a5d7 100644 (file)
 // interpreted as representing official policies, either expressed
 // or implied, of GRNET S.A.
 
+#define PithosNodeStateFresh 0
+#define PithosNodeStateRefreshNeeded 1
+#define PithosNodeStateRefreshing 2
+#define PithosNodeStateRefreshFinished 3
+
 @interface PithosNode : NSObject {
+    NSInteger freshness;
+    
     NSString *url;    
     
     NSMutableArray *children;
-    BOOL childrenDirty;
-    NSMutableArray *previousChildren;
+    NSMutableArray *newChildren;
     
     NSString *displayName;
     BOOL isLeafItem;
@@ -60,5 +66,6 @@
 @property(readonly) NSString *version;
 
 - (void)invalidateChildren;
+- (void)invalidateChildrenRecursive;
 
-@end
+@end
\ No newline at end of file
index bc1cc4e..42c0567 100644 (file)
@@ -46,7 +46,7 @@
 
 - (id)init {
     if ((self == [super init])) {
-        childrenDirty = YES;
+        freshness = PithosNodeStateRefreshNeeded;
         isLeafItem = NO;
     }
     return self;
 - (void)dealloc {
     [icon release];
     [displayName release];
-    [previousChildren release];
+    [newChildren release];
     [children release];
     [url release];
     [super dealloc];
 }
 
 - (BOOL)isEqual:(id)anObject {
-    if ([anObject isKindOfClass:[self class]]) {
-        return [((PithosNode *)anObject).url isEqual:self.url];
-    }
-    return NO;
+    return ([anObject isKindOfClass:[self class]] && [((PithosNode *)anObject).url isEqual:self.url]);
 }
 
 - (NSUInteger)hash {
 }
 
 - (void)invalidateChildren {
-    childrenDirty = YES;
-    for (PithosNode *child in children) {
-        [child invalidateChildren];
+    if (freshness == PithosNodeStateFresh)
+        freshness = PithosNodeStateRefreshNeeded;
+}
+
+- (void)invalidateChildrenRecursive {    
+    if (freshness == PithosNodeStateFresh) {
+        for (PithosNode *child in children) {
+            [child invalidateChildrenRecursive];
+        }
+        freshness = PithosNodeStateRefreshNeeded;
     }
 }
 
index f51f68d..d868d1a 100644 (file)
@@ -36,8 +36,8 @@
 // or implied, of GRNET S.A.
 
 #import "PithosNode.h"
-#import "ASIPithosContainer.h"
-#import "ASIPithosObject.h"
+@class ASIPithosContainer;
+@class ASIPithosObject;
 
 @interface PithosObjectNode : PithosNode {
     ASIPithosContainer *pithosContainer;
@@ -46,4 +46,7 @@
 
 - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer pithosObject:(ASIPithosObject *)aPithosObject;
 
-@end
+@property (retain) ASIPithosContainer *pithosContainer;
+@property (retain) ASIPithosObject *pithosObject;
+
+@end
\ No newline at end of file
index 8cd4774..71df703 100644 (file)
 
 #import "PithosObjectNode.h"
 #import "ASIPithosRequest.h"
+#import "ASIPithosContainer.h"
+#import "ASIPithosObject.h"
 
 @implementation PithosObjectNode
+@synthesize pithosContainer, pithosObject;
 
 #pragma mark -
 #pragma mark Object Lifecycle
@@ -73,6 +76,7 @@
 
 - (NSString *)displayName {
     if (displayName == nil) {
+        // XXX check if there are problems with . or other special characters
         displayName = [pithosObject.name lastPathComponent];
         if([pithosObject.name hasSuffix:@"/"])
             displayName = [displayName stringByAppendingString:@"/"];
index 89f7ef9..e62f6e3 100644 (file)
@@ -36,7 +36,7 @@
 // or implied, of GRNET S.A.
 
 #import "PithosContainerNode.h"
-#import "ASIPithosObject.h"
+@class ASIPithosObject;
 
 @interface PithosSubdirNode : PithosContainerNode {
     ASIPithosObject *pithosObject;
@@ -44,4 +44,6 @@
 
 - (id)initWithPithosContainer:(ASIPithosContainer *)aPithosContainer pithosObject:(ASIPithosObject *)aPithosObject;
 
-@end
+@property (retain) ASIPithosObject *pithosObject;
+
+@end
\ No newline at end of file
index 94bcec1..b96d7ff 100644 (file)
 
 #import "PithosSubdirNode.h"
 #import "ASIPithosRequest.h"
+#import "ASIPithosContainer.h"
+#import "ASIPithosObject.h"
 
 static NSImage *sharedIcon = nil;
 
 @implementation PithosSubdirNode
+@synthesize pithosObject;
 
 + (void)initialize {
        if (self == [PithosSubdirNode class])
@@ -54,7 +57,6 @@ static NSImage *sharedIcon = nil;
     if ((self = [super init])) {
         pithosContainer = [aPithosContainer retain];
         pithosObject = [aPithosObject retain];
-        refreshing = NO;
         prefix = [[pithosObject.name substringToIndex:([pithosObject.name length] - 1)] retain];
         childrenUpdatedNotificationName = @"PithosSubdirNodeChildrenUpdated";
     }
@@ -76,6 +78,7 @@ static NSImage *sharedIcon = nil;
 }
 
 - (NSString *)displayName {
+    // XXX check if there are problems with . or other special characters
     return [pithosObject.name lastPathComponent];
 }