Revision d8426ffb

b/pithos-apple-common
1
Subproject commit 308855b44f430202033eda90f597f6abdae5ea80
1
Subproject commit 097cb8319ef7a831c06f6154df3c63b043382ff2
b/pithos-macos.xcodeproj/project.pbxproj
48 48
		614299A914CEF0E7008D973A /* ASIPithos.m in Sources */ = {isa = PBXBuildFile; fileRef = 614299A814CEF0E7008D973A /* ASIPithos.m */; };
49 49
		61433BC9141BA1CE00CD978D /* HashMapHash.m in Sources */ = {isa = PBXBuildFile; fileRef = 61433BC8141BA1CE00CD978D /* HashMapHash.m */; };
50 50
		614592BC1417CE70002E7A8C /* ASIPithosAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = 614592BB1417CE70002E7A8C /* ASIPithosAccount.m */; };
51
		614EEC8414E16EB5009DEFCC /* PithosAccount.m in Sources */ = {isa = PBXBuildFile; fileRef = 614EEC8314E16EB5009DEFCC /* PithosAccount.m */; };
51 52
		6152D08C143200CC00803874 /* PithosSharingAccountsNode.m in Sources */ = {isa = PBXBuildFile; fileRef = 6152D08B143200CC00803874 /* PithosSharingAccountsNode.m */; };
52 53
		6152D092143334CC00803874 /* AllowedToBoolTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6152D091143334CC00803874 /* AllowedToBoolTransformer.m */; };
53 54
		6152D095143334E000803874 /* SharingAccountBoolTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 6152D094143334E000803874 /* SharingAccountBoolTransformer.m */; };
......
165 166
		61433BC8141BA1CE00CD978D /* HashMapHash.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HashMapHash.m; path = "pithos-macos/HashMapHash.m"; sourceTree = "<group>"; };
166 167
		614592BA1417CE70002E7A8C /* ASIPithosAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIPithosAccount.h; sourceTree = "<group>"; };
167 168
		614592BB1417CE70002E7A8C /* ASIPithosAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIPithosAccount.m; sourceTree = "<group>"; };
169
		614EEC8214E16EB5009DEFCC /* PithosAccount.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PithosAccount.h; sourceTree = "<group>"; };
170
		614EEC8314E16EB5009DEFCC /* PithosAccount.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PithosAccount.m; sourceTree = "<group>"; };
168 171
		6152D08A143200CB00803874 /* PithosSharingAccountsNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PithosSharingAccountsNode.h; sourceTree = "<group>"; };
169 172
		6152D08B143200CC00803874 /* PithosSharingAccountsNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PithosSharingAccountsNode.m; sourceTree = "<group>"; };
170 173
		6152D090143334CC00803874 /* AllowedToBoolTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AllowedToBoolTransformer.h; path = "pithos-macos/AllowedToBoolTransformer.h"; sourceTree = "<group>"; };
......
283 286
		610DD2FB13E6BB2000ED982F /* pithos-macos */ = {
284 287
			isa = PBXGroup;
285 288
			children = (
289
				610DD30713E6BB2000ED982F /* pithos_macosAppDelegate.h */,
290
				610DD30813E6BB2000ED982F /* pithos_macosAppDelegate.m */,
291
				614EEC8214E16EB5009DEFCC /* PithosAccount.h */,
292
				614EEC8314E16EB5009DEFCC /* PithosAccount.m */,
286 293
				61F040E71447218F00A0C788 /* PithosBrowser */,
287 294
				61F040E51447217100A0C788 /* PithosSyncDaemon */,
288 295
				61F040E8144721B200A0C788 /* PithosActivityFacility */,
289 296
				61F1C5DB1444A8CF00C1E6EB /* PithosNodes */,
290 297
				61F1C5DD1444A92B00C1E6EB /* PithosNodeInfoControllers */,
291 298
				610DD2FC13E6BB2000ED982F /* Supporting Files */,
292
				610DD30713E6BB2000ED982F /* pithos_macosAppDelegate.h */,
293
				610DD30813E6BB2000ED982F /* pithos_macosAppDelegate.m */,
294 299
				610DD30A13E6BB2000ED982F /* MainMenu.xib */,
295 300
				61C24BEA14161EC0007004DC /* PithosUtilities.h */,
296 301
				61C24BEB14161EC3007004DC /* PithosUtilities.m */,
......
555 560
		610DD2E813E6BB2000ED982F /* Project object */ = {
556 561
			isa = PBXProject;
557 562
			attributes = {
558
				LastUpgradeCheck = 0420;
563
				LastUpgradeCheck = 0430;
559 564
				ORGANIZATIONNAME = koomasi;
560 565
			};
561 566
			buildConfigurationList = 610DD2EB13E6BB2000ED982F /* Build configuration list for PBXProject "pithos-macos" */;
......
659 664
				6154BF531456EE4900EE353A /* DirPathFileURLTransformer.m in Sources */,
660 665
				613BA8631461520E00FACAA5 /* NonEmptyStringFormatter.m in Sources */,
661 666
				614299A914CEF0E7008D973A /* ASIPithos.m in Sources */,
667
				614EEC8414E16EB5009DEFCC /* PithosAccount.m in Sources */,
662 668
			);
663 669
			runOnlyForDeploymentPostprocessing = 0;
664 670
		};
b/pithos-macos/LastCompletedSyncTransformer.m
2 2
//  LastCompletedSyncTransformer.m
3 3
//  pithos-macos
4 4
//
5
// Copyright 2011 GRNET S.A. All rights reserved.
5
// Copyright 2011-2012 GRNET S.A. All rights reserved.
6 6
//
7 7
// Redistribution and use in source and binary forms, with or
8 8
// without modification, are permitted provided that the following
......
49 49

  
50 50
- (id)transformedValue:(id)value {
51 51
    if (value == nil)
52
		return @"Last Sync: -";
52
		return @"-";
53 53
    
54 54
    NSCalendar *calendar = [NSCalendar currentCalendar];
55 55
    NSDateComponents *comps = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDate date]];
......
59 59
    NSTimeInterval timeInterval = [[calendar dateFromComponents:comps] timeIntervalSinceDate:(NSDate *)value];
60 60
    if (timeInterval < 86400) {
61 61
        // Today
62
        return [NSString stringWithFormat:@"Last Sync: Today %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value 
62
        return [NSString stringWithFormat:@"Today %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value 
63 63
                                                                                                     dateStyle:NSDateFormatterNoStyle 
64 64
                                                                                                     timeStyle:NSDateFormatterShortStyle]];
65 65
    } else if (timeInterval < 172800) {
66 66
        // Yesterday
67
        return [NSString stringWithFormat:@"Last Sync: Yesterday %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value 
67
        return [NSString stringWithFormat:@"Yesterday %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value 
68 68
                                                                                           dateStyle:NSDateFormatterNoStyle 
69 69
                                                                                           timeStyle:NSDateFormatterShortStyle]];
70 70
    } else {
71
        return [NSString stringWithFormat:@"Last Sync: %@", [NSDateFormatter localizedStringFromDate:(NSDate *)value 
71
        return [NSString stringWithFormat:@"%@", [NSDateFormatter localizedStringFromDate:(NSDate *)value 
72 72
                                                                                           dateStyle:NSDateFormatterShortStyle 
73 73
                                                                                           timeStyle:NSDateFormatterShortStyle]];
74 74
    }
b/pithos-macos/PithosAccount.h
1
//
2
//  PithosAccount.h
3
//  pithos-macos
4
//
5
// Copyright 2012 GRNET S.A. All rights reserved.
6
//
7
// Redistribution and use in source and binary forms, with or
8
// without modification, are permitted provided that the following
9
// conditions are met:
10
// 
11
//   1. Redistributions of source code must retain the above
12
//      copyright notice, this list of conditions and the following
13
//      disclaimer.
14
// 
15
//   2. Redistributions in binary form must reproduce the above
16
//      copyright notice, this list of conditions and the following
17
//      disclaimer in the documentation and/or other materials
18
//      provided with the distribution.
19
// 
20
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
// POSSIBILITY OF SUCH DAMAGE.
32
// 
33
// The views and conclusions contained in the software and
34
// documentation are those of the authors and should not be
35
// interpreted as representing official policies, either expressed
36
// or implied, of GRNET S.A.
37

  
38
#import <Foundation/Foundation.h>
39
@class PithosSyncDaemon;
40
@class ASIPithos;
41
@class PithosAccountNode;
42

  
43
@interface PithosAccount : NSObject <NSCoding> {
44
    NSString *uniqueName;
45
    BOOL active;
46
    NSString *name;
47
    
48
    BOOL syncActive;
49
    NSString *syncDirectoryPath;
50
    NSString *syncContainerName;
51
    NSDate *syncLastCompleted;
52
    PithosSyncDaemon *syncDaemon;
53
        
54
    // Base for all necessary URLs, default "https://plus.pithos.grnet.gr"
55
    NSString *serverURL;
56
    // Appended to serverURL to get storageURLPrefix and authURL, default "v1"
57
    // Can be overriden by setting directly storageURLPrefix and authURL
58
    NSString *versionResource;
59
    // Appended to serverURL to get loginURLPrefix, default "login"
60
    // Can be overriden by setting directly loginURLPrefix
61
    NSString *loginResource;
62
    // Appended to serverURL to get publicURLPrefix, default nil
63
    // Can be overriden by setting directly publicURLPrefix
64
    NSString *publicResource;
65

  
66
    NSString *authUser;
67
    NSString *authToken;
68
    NSString *storageURLPrefix;
69
    NSString *authURL;
70
    NSString *publicURLPrefix;
71
    NSString *loginURLPrefix;
72
    
73
    ASIPithos *pithos;
74
    PithosAccountNode *accountNode;
75
    
76
    BOOL updatePithos;
77
    BOOL resetSyncDaemonLocalState;
78
}
79

  
80
@property (nonatomic, retain) NSString *uniqueName;
81
@property (assign) BOOL active;
82
@property (nonatomic, retain) NSString *name;
83

  
84
@property (nonatomic, assign) BOOL syncActive;
85
@property (nonatomic, retain) NSString *syncDirectoryPath;
86
@property (nonatomic, retain) NSString *syncContainerName;
87
@property (nonatomic, retain) NSDate *syncLastCompleted;
88
@property (nonatomic, retain) PithosSyncDaemon *syncDaemon;
89

  
90
@property (nonatomic, retain) NSString *serverURL;
91
@property (retain) NSString *versionResource;
92
@property (retain) NSString *loginResource;
93
@property (retain) NSString *publicResource;
94

  
95
@property (nonatomic, retain) NSString *authUser;
96
@property (nonatomic, retain) NSString *authToken;
97
@property (nonatomic, retain) NSString *storageURLPrefix;
98
@property (nonatomic, retain) NSString *authURL;
99
@property (nonatomic, retain) NSString *publicURLPrefix;
100
@property (nonatomic, retain) NSString *loginURLPrefix;
101

  
102
@property (readonly) ASIPithos *pithos;
103
@property (readonly) PithosAccountNode *accountNode;
104

  
105
+ (id)pithosAccount;
106

  
107
- (BOOL)urlIsValid:(NSString *)urlString;
108
- (void)authenticateWithServerURL:(NSString *)aServerURL authUser:(NSString *)anAuthUser authToken:(NSString *)anAuthToken;
109
- (void)loginWithServerURL:(NSString *)aServerURL;
110
- (void)updateSyncWithSyncActive:(BOOL)aSyncActive syncDirectoryPath:(NSString *)aSyncDirectoryPath;
111

  
112
@end
b/pithos-macos/PithosAccount.m
1
//
2
//  PithosAccount.m
3
//  pithos-macos
4
//
5
// Copyright 2012 GRNET S.A. All rights reserved.
6
//
7
// Redistribution and use in source and binary forms, with or
8
// without modification, are permitted provided that the following
9
// conditions are met:
10
// 
11
//   1. Redistributions of source code must retain the above
12
//      copyright notice, this list of conditions and the following
13
//      disclaimer.
14
// 
15
//   2. Redistributions in binary form must reproduce the above
16
//      copyright notice, this list of conditions and the following
17
//      disclaimer in the documentation and/or other materials
18
//      provided with the distribution.
19
// 
20
// THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
21
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
24
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
27
// USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28
// AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31
// POSSIBILITY OF SUCH DAMAGE.
32
// 
33
// The views and conclusions contained in the software and
34
// documentation are those of the authors and should not be
35
// interpreted as representing official policies, either expressed
36
// or implied, of GRNET S.A.
37

  
38
#import "PithosAccount.h"
39
#import "PithosSyncDaemon.h"
40
#import "ASIPithos.h"
41
#import "PithosAccountNode.h"
42
#import "pithos_macosAppDelegate.h"
43

  
44
@interface PithosAccount (Internal)
45
- (BOOL)urlIsValid:(NSString *)urlString;
46
@end
47

  
48
@implementation PithosAccount
49
@synthesize uniqueName, active, name;
50
@synthesize syncActive, syncDirectoryPath, syncContainerName, syncLastCompleted, syncDaemon;
51
@synthesize serverURL, versionResource, loginResource, publicResource;
52
@synthesize authUser, authToken, storageURLPrefix, authURL, loginURLPrefix, publicURLPrefix;
53
@synthesize pithos, accountNode;
54

  
55
#pragma mark -
56
#pragma mark Object Lifecycle
57

  
58
+ (id)pithosAccount {
59
    PithosAccount *pithosAccount = [[[self alloc] init] autorelease];
60
    pithosAccount.uniqueName = [NSString stringWithFormat:@"pithosAccount-%f", [NSDate timeIntervalSinceReferenceDate]];
61
    pithosAccount.versionResource = [NSString stringWithString:@"v1"];
62
    pithosAccount.loginResource = [NSString stringWithString:@"login"];
63
    return pithosAccount;
64
}
65

  
66
- (void)dealloc {
67
    [accountNode release];
68
    [pithos release];
69
    [publicURLPrefix release];
70
    [loginURLPrefix release];
71
    [authURL release];
72
    [storageURLPrefix release];
73
    [authToken release];
74
    [authUser release];
75
    [publicResource release];
76
    [loginResource release];
77
    [versionResource release];
78
    [serverURL release];
79
    [syncDaemon release];
80
    [syncLastCompleted release];
81
    [syncContainerName release];
82
    [syncDirectoryPath release];
83
    [name release];
84
    [uniqueName release];
85
    [super dealloc];
86
}
87

  
88
- (NSString *)description {
89
    return [NSString stringWithFormat:@"uniqueName: %@, active: %d, name: %@, syncActive: %d, syncDirectoryPath: %@, syncContainerName: %@, syncLastCompleted: %@, serverURL: %@, versionResource: %@, loginResource: %@, publicResource: %@, authUser: %@, authToken: %@, storageURLPrefix: %@, authURL: %@, loginURLPrefix: %@, publicURLPrefix: %@", 
90
            uniqueName, active, name, syncActive, syncDirectoryPath, syncContainerName, syncLastCompleted, serverURL, versionResource, loginResource, publicResource, authUser, authToken, storageURLPrefix, authURL, loginURLPrefix, publicURLPrefix];
91
}
92

  
93
#pragma mark -
94
#pragma mark Internal
95

  
96
- (BOOL)urlIsValid:(NSString *)urlString {
97
    if (urlString) {
98
        NSURL *url = [NSURL URLWithString:urlString];
99
        if (url && url.scheme && url.host)
100
            return YES;
101
    }
102
    return NO;
103
}
104

  
105
#pragma mark -
106
#pragma mark Properties
107

  
108
- (NSString *)name {
109
    if (![name length]) {
110
        [name release];
111
        NSDictionary *pithosAccountsDictionary = [(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] pithosAccountsDictionary];
112
        NSString *namePrefix = [NSString stringWithString:@"okeanos"];
113
        NSUInteger nameSuffix = 1;
114
        name = [NSString stringWithString:@"okeanos"];
115
        NSString *documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
116
        NSFileManager *fileManager = [NSFileManager defaultManager];
117
        while ([pithosAccountsDictionary objectForKey:name] || 
118
               [fileManager fileExistsAtPath:[documentsDirectoryPath stringByAppendingPathComponent:name]]) {
119
            name = [NSString stringWithFormat:@"%@%d", namePrefix, ++nameSuffix];
120
        }
121
        [name retain];
122
    }
123
    return name;
124
}
125

  
126
- (void)setName:(NSString *)aName {
127
    NSMutableDictionary *pithosAccountsDictionary = [(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] pithosAccountsDictionary];
128
    if (![self.name isEqualToString:aName] && [aName length] && ![pithosAccountsDictionary objectForKey:aName]) {
129
        [pithosAccountsDictionary setObject:self forKey:aName];
130
        [pithosAccountsDictionary removeObjectForKey:name];
131
        [name release];
132
        name = [aName retain];
133
    }
134
}
135

  
136
- (BOOL)syncActive {
137
    if (active)
138
        return syncActive;
139
    else
140
        return NO;
141
}
142

  
143
- (void)setSyncActive:(BOOL)aSyncActive {
144
    syncActive = aSyncActive;
145
    if (syncDaemon && !self.syncActive)
146
        [syncDaemon resetDaemon];
147
}
148

  
149
- (NSString *)syncDirectoryPath {
150
    if (![syncDirectoryPath length]) {
151
        [syncDirectoryPath release];
152
        syncDirectoryPath = [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] 
153
                              stringByAppendingPathComponent:self.name] retain];
154
    }
155
    return syncDirectoryPath;
156
}
157

  
158
- (void)setSyncDirectoryPath:(NSString *)aSyncDirectoryPath {
159
    if (![self.syncDirectoryPath isEqualToString:aSyncDirectoryPath] && [aSyncDirectoryPath length]) {
160
        BOOL isDirectory;
161
        if (![[NSFileManager defaultManager] fileExistsAtPath:aSyncDirectoryPath isDirectory:&isDirectory] || isDirectory) {
162
            [syncDirectoryPath release];
163
            syncDirectoryPath = [aSyncDirectoryPath retain];
164
        } else {
165
            return;
166
        }
167

  
168
        @synchronized(self) {
169
            resetSyncDaemonLocalState = YES;
170
            [syncLastCompleted release];
171
            syncLastCompleted = nil;
172
        }
173
    }
174
}
175

  
176
- (NSString *)syncContainerName {
177
    if (![syncContainerName length]) {
178
        [syncContainerName release];
179
        syncContainerName = [[NSString stringWithString:@"pithos"] retain];
180
    }        
181
    return syncContainerName;
182
}
183

  
184
- (void)setSyncContainerName:(NSString *)aSyncContainerName {
185
    if (![self.syncContainerName isEqualToString:aSyncContainerName] && [aSyncContainerName length]) {
186
        [syncContainerName release];
187
        syncContainerName = [aSyncContainerName retain];
188
        
189
        @synchronized(self) {
190
            resetSyncDaemonLocalState = YES;
191
            [syncLastCompleted release];
192
            syncLastCompleted = nil;
193
        }
194
    }
195
}
196

  
197
- (NSDate *)syncLastCompleted {
198
    if (self.syncDaemon.lastCompletedSync && ![self.syncDaemon.lastCompletedSync isEqualToDate:syncLastCompleted]) {
199
        [syncLastCompleted release];
200
        syncLastCompleted = [self.syncDaemon.lastCompletedSync copy];
201
    }
202
    return syncLastCompleted;
203
}
204

  
205
- (PithosSyncDaemon *)syncDaemon {
206
    @synchronized(self) {
207
        if (self.syncActive && !syncDaemon)
208
            syncDaemon = [[PithosSyncDaemon alloc] initWithDirectoryPath:self.syncDirectoryPath 
209
                                                           pithosAccount:self 
210
                                                           containerName:self.syncContainerName 
211
                                                         resetLocalState:resetSyncDaemonLocalState];
212
        resetSyncDaemonLocalState = NO;
213
    }
214
    return syncDaemon;
215
}
216

  
217
- (NSString *)serverURL {
218
    if (![self urlIsValid:serverURL]) {
219
        [serverURL release];
220
        serverURL = [[NSString stringWithString:@"https://plus.pithos.grnet.gr"] retain];
221
    }
222
    return serverURL;
223
}
224

  
225
- (void)setServerURL:(NSString *)aServerURL {
226
    if (![self.serverURL isEqualToString:aServerURL] && [self urlIsValid:aServerURL]) {
227
        [serverURL release];
228
        serverURL = [aServerURL retain];
229
        [storageURLPrefix release];
230
        storageURLPrefix = nil;
231
        [authURL release];
232
        authURL = nil;
233
        [publicURLPrefix release];
234
        publicURLPrefix = nil;
235
        [loginURLPrefix release];
236
        loginURLPrefix = nil;
237

  
238
        @synchronized(self) {
239
            updatePithos = YES;
240
            resetSyncDaemonLocalState = YES;
241
            [syncLastCompleted release];
242
            syncLastCompleted = nil;
243
        }
244
    }
245
}
246

  
247
- (void)setAuthUser:(NSString *)anAuthUser {
248
    if ([anAuthUser length] && ![anAuthUser isEqualToString:authUser]) {
249
        [authUser release];
250
        authUser = [anAuthUser retain];
251
        
252
        @synchronized(self) {
253
            updatePithos = YES;
254
            resetSyncDaemonLocalState = YES;
255
            [syncLastCompleted release];
256
            syncLastCompleted = nil;
257

  
258
        }
259
    }
260
}
261

  
262
- (void)setAuthToken:(NSString *)anAuthToken {
263
    if ([anAuthToken length] && ![anAuthToken isEqualToString:authToken]) {
264
        [authToken release];
265
        authToken = [anAuthToken retain];
266
        
267
        @synchronized(self) {
268
            updatePithos = YES;
269
        }
270
    }
271
}
272

  
273
- (NSString *)storageURLPrefix {
274
    if (![self urlIsValid:storageURLPrefix]) {
275
        [storageURLPrefix release];
276
        if (versionResource)
277
            storageURLPrefix = [[self.serverURL stringByAppendingFormat:@"/%@", versionResource] retain];
278
        else
279
            storageURLPrefix = [self.serverURL copy];
280
    }
281
    return storageURLPrefix;
282
}
283

  
284
- (void)setStorageURLPrefix:(NSString *)aStorageURLPrefix {
285
    if (![self.storageURLPrefix isEqualToString:aStorageURLPrefix] && [self urlIsValid:aStorageURLPrefix]) {
286
        [storageURLPrefix release];
287
        storageURLPrefix = [aStorageURLPrefix retain];
288
    }
289
}
290

  
291
- (NSString *)authURL {
292
    if (![self urlIsValid:authURL]) {
293
        [authURL release];
294
        if (versionResource)
295
            authURL = [[self.serverURL stringByAppendingFormat:@"/%@", versionResource] retain];
296
        else
297
            authURL = [self.serverURL copy];
298
    }
299
    return authURL;
300
}
301

  
302
- (void)setAuthURL:(NSString *)anAuthURL {
303
    if (![self.authURL isEqualToString:anAuthURL] && [self urlIsValid:anAuthURL]) {
304
        [authURL release];
305
        authURL = [anAuthURL retain];
306
    }
307
}
308

  
309
- (NSString *)publicURLPrefix {
310
    if (![self urlIsValid:publicURLPrefix]) {
311
        [publicURLPrefix release];
312
        if (publicResource)
313
            publicURLPrefix = [[self.serverURL stringByAppendingFormat:@"/%@", publicResource] retain];
314
        else
315
            publicURLPrefix = [self.serverURL copy];
316
    }
317
    return publicURLPrefix;
318
}
319

  
320
- (void)setPublicURLPrefix:(NSString *)aPublicURLPrefix {
321
    if (![self.publicURLPrefix isEqualToString:aPublicURLPrefix] && [self urlIsValid:aPublicURLPrefix]) {
322
        [publicURLPrefix release];
323
        publicURLPrefix = [aPublicURLPrefix retain];
324
    }
325
}
326

  
327
- (NSString *)loginURLPrefix {
328
    if (![self urlIsValid:loginURLPrefix]) {
329
        [loginURLPrefix release];
330
        if (loginResource)
331
            loginURLPrefix = [[self.serverURL stringByAppendingFormat:@"/%@", loginResource] retain];
332
        else
333
            loginURLPrefix = [self.serverURL copy];
334
    }
335
    return loginURLPrefix;
336
}
337

  
338
- (void)setLoginURLPrefix:(NSString *)aLoginURLPrefix {
339
    if (![self.loginURLPrefix isEqualToString:aLoginURLPrefix] && [self urlIsValid:aLoginURLPrefix]) {
340
        [loginURLPrefix release];
341
        loginURLPrefix = [aLoginURLPrefix retain];
342
    }
343
}
344

  
345
- (ASIPithos *)pithos {
346
    @synchronized(self) {
347
        if (!pithos || updatePithos) {
348
            [pithos release];
349
            pithos = [[ASIPithos pithos] retain];
350
            pithos.authUser = authUser;
351
            pithos.authToken = authToken;
352
            pithos.storageURLPrefix = self.storageURLPrefix;
353
            pithos.authURL = self.authURL;
354
            pithos.publicURLPrefix = self.publicURLPrefix;
355

  
356
            if (accountNode && ![accountNode.pithos isEqualTo:pithos]) {
357
                accountNode.pithos = pithos;
358
                if (active)
359
                    [accountNode refreshInfo];
360
            }
361
            
362
            updatePithos = NO;
363
        }
364
    }
365
    return pithos;
366
}
367

  
368
- (PithosAccountNode *)accountNode {
369
    if (!accountNode) {
370
        accountNode = [[PithosAccountNode alloc] initWithPithos:self.pithos];
371
    }
372
    return accountNode;
373
}
374

  
375
#pragma mark -
376
#pragma mark Actions
377

  
378
- (void)authenticateWithServerURL:(NSString *)aServerURL authUser:(NSString *)anAuthUser authToken:(NSString *)anAuthToken {
379
    self.serverURL = aServerURL;
380
    self.authUser = anAuthUser;
381
    self.authToken = anAuthToken;
382
    NSLog(@"Account: %@\nauthentication", self);
383
    if (![authUser length] || ![authToken length]) {
384
        self.active = NO;
385
        self.syncActive = NO;
386
        // XXX Show preferences with self as the selected account?
387
    } else  {
388
        self.active = YES;
389
        if (syncDaemon) {
390
            self.syncDaemon.pithos = self.pithos;
391
            if (self.syncActive)
392
                [self.syncDaemon startDaemon];
393
        }
394
    }
395
}
396

  
397
- (void)loginWithServerURL:(NSString *)aServerURL {
398
    self.serverURL = aServerURL;
399
    NSProcessInfo *processInfo = [NSProcessInfo processInfo];
400
    NSString *loginURL = [NSString stringWithFormat:@"%@?next=pithos://%@_%d/%@", 
401
                          self.loginURLPrefix, [processInfo processName], [processInfo processIdentifier], self.name];
402
    NSLog(@"Account: %@\nloginURL: %@", self, loginURL);
403
    [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:loginURL]];
404
}
405

  
406
- (void)updateSyncWithSyncActive:(BOOL)aSyncActive syncDirectoryPath:(NSString *)aSyncDirectoryPath {
407
    self.syncDirectoryPath = aSyncDirectoryPath;
408
    self.syncActive = aSyncActive;
409
    if (syncDaemon) {
410
        self.syncDaemon.directoryPath = self.syncDirectoryPath;
411
        if (self.syncActive)
412
            [self.syncDaemon startDaemon];
413
    }    
414
}
415

  
416
#pragma mark -
417
#pragma mark NSCoding
418

  
419
- (id)initWithCoder:(NSCoder *)decoder {
420
    if ((self = [super init])) {
421
        self.uniqueName = [decoder decodeObjectForKey:@"uniqueName"];
422
        self.active = [decoder decodeBoolForKey:@"active"];
423
        name = [[decoder decodeObjectForKey:@"name"] retain];
424

  
425
        self.syncActive = [decoder decodeBoolForKey:@"syncActive"];
426
        self.syncDirectoryPath = [decoder decodeObjectForKey:@"syncDirectoryPath"];
427
        self.syncContainerName = [decoder decodeObjectForKey:@"syncContainerName"];
428
        self.syncLastCompleted = [decoder decodeObjectForKey:@"syncLastCompleted"];
429
        
430
        self.serverURL = [decoder decodeObjectForKey:@"serverURL"];
431
        self.versionResource = [decoder decodeObjectForKey:@"versionResource"];
432
        self.loginResource = [decoder decodeObjectForKey:@"loginResource"];
433
        self.publicResource = [decoder decodeObjectForKey:@"publicResource"];
434
        
435
        self.authUser = [decoder decodeObjectForKey:@"authUser"];
436
        self.authToken = [decoder decodeObjectForKey:@"authToken"];
437
        self.storageURLPrefix = [decoder decodeObjectForKey:@"storageURLPrefix"];
438
        self.authURL = [decoder decodeObjectForKey:@"authURL"];
439
        self.publicURLPrefix = [decoder decodeObjectForKey:@"publicURLPrefix"];
440
        self.loginURLPrefix = [decoder decodeObjectForKey:@"loginURLPrefix"];
441
        
442
        if (![authUser length] || ![authToken length] || ![self.storageURLPrefix length])
443
            self.active = NO;
444
        
445
        resetSyncDaemonLocalState = NO;
446
    }
447
    return self;
448
}
449

  
450
- (void)encodeWithCoder:(NSCoder *)encoder {
451
    [encoder encodeObject:uniqueName forKey:@"uniqueName"];
452
    [encoder encodeBool:active forKey:@"active"];
453
    [encoder encodeObject:name forKey:@"name"];
454
    
455
    [encoder encodeBool:syncActive forKey:@"syncActive"];
456
    [encoder encodeObject:syncDirectoryPath forKey:@"syncDirectoryPath"];
457
    [encoder encodeObject:syncContainerName forKey:@"syncContainerName"];
458
    [encoder encodeObject:self.syncLastCompleted forKey:@"syncLastCompleted"];
459

  
460
    [encoder encodeObject:serverURL forKey:@"serverURL"];
461
    [encoder encodeObject:versionResource forKey:@"versionResource"];
462
    [encoder encodeObject:publicResource forKey:@"publicResource"];
463
    [encoder encodeObject:loginResource forKey:@"loginResource"];
464
    
465
    [encoder encodeObject:authUser forKey:@"authUser"];
466
    [encoder encodeObject:authToken forKey:@"authToken"];
467
    [encoder encodeObject:storageURLPrefix forKey:@"storageURLPrefix"];
468
    [encoder encodeObject:authURL forKey:@"authURL"];
469
    [encoder encodeObject:publicURLPrefix forKey:@"publicURLPrefix"];
470
    [encoder encodeObject:loginURLPrefix forKey:@"loginURLPrefix"];
471
}
472

  
473
@end
b/pithos-macos/PithosAccountNode.m
81 81
#pragma mark -
82 82
#pragma mark Properties
83 83

  
84
- (void)setPithos:(ASIPithos *)aPithos {
85
    if (aPithos && ![aPithos isEqualTo:pithos]) {
86
        [pithos release];
87
        pithos = [aPithos retain];
88
        [url release];
89
        url = nil;
90
    }
91
}
92

  
84 93
- (NSString *)url {
85 94
    if (url == nil)
86 95
        url = [[NSString alloc] initWithFormat:@"%@%@", 
......
298 307

  
299 308
- (void)accountMetadataRequestFailed:(ASIPithosAccountRequest *)request {
300 309
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
301
    if ([request isEqualTo:applyMetadataAccountRequest]) {
302
        [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataAccountRequest];
303
        @synchronized(self) {
304
            [applyMetadataAccountRequest release];
305
            applyMetadataAccountRequest = nil;
310
    NSUInteger retries = [[request.userInfo objectForKey:@"retries"] unsignedIntegerValue];
311
    if (retries > 0) {
312
        ASIPithosAccountRequest *newRequest = (ASIPithosAccountRequest *)[PithosUtilities copyRequest:request];
313
        [(NSMutableDictionary *)(newRequest.userInfo)setObject:[NSNumber numberWithUnsignedInteger:(--retries)] forKey:@"retries"];
314
        if ([request isEqualTo:applyMetadataAccountRequest]) {
315
            @synchronized(self) {
316
                [applyMetadataAccountRequest release];
317
                applyMetadataAccountRequest = newRequest;
318
            }
319
        } else if ([request isEqualTo:refreshMetadataAccountRequest]) {
320
            @synchronized(self) {
321
                [refreshMetadataAccountRequest release];
322
                refreshMetadataAccountRequest = newRequest;
323
            }
306 324
        }
307
    } else if ([request isEqualTo:refreshMetadataAccountRequest]) {
308
        [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataAccountRequest];
309
        @synchronized(self) {
310
            [refreshMetadataAccountRequest release];
311
            refreshMetadataAccountRequest = nil;
325
        [[PithosUtilities prepareRequest:newRequest priority:[[newRequest.userInfo objectForKey:@"priority"] integerValue]] startAsynchronous];
326
    } else {
327
        if ([request isEqualTo:applyMetadataAccountRequest]) {
328
            dispatch_async(dispatch_get_main_queue(), ^{
329
                [PithosUtilities httpRequestErrorAlertWithRequest:applyMetadataAccountRequest];
330
            });
331
            @synchronized(self) {
332
                [applyMetadataAccountRequest release];
333
                applyMetadataAccountRequest = nil;
334
            }
335
        } else if ([request isEqualTo:refreshMetadataAccountRequest]) {
336
            dispatch_async(dispatch_get_main_queue(), ^{
337
                [PithosUtilities httpRequestErrorAlertWithRequest:refreshMetadataAccountRequest];
338
            });
339
            @synchronized(self) {
340
                [refreshMetadataAccountRequest release];
341
                refreshMetadataAccountRequest = nil;
342
            }
312 343
        }
313 344
    }
314 345
    [pool drain];
b/pithos-macos/PithosActivity.h
36 36
// or implied, of GRNET S.A.
37 37

  
38 38
#import <Foundation/Foundation.h>
39
@class PithosAccount;
39 40

  
40 41
typedef enum  {
41 42
    PithosActivityUpload, 
......
52 53
    NSString *message;
53 54
    NSUInteger totalBytes;
54 55
    NSUInteger currentBytes;
56
    PithosAccount *pithosAccount;
55 57
}
56 58

  
57
- (id)initWithType:(PithosActivityType)aType;
59
- (id)initWithType:(PithosActivityType)aType pithosAccount:(PithosAccount *)aPithosAccount;
58 60

  
59 61
@property (nonatomic, assign) PithosActivityType type;
60 62
@property (nonatomic, copy) NSString *message;
61 63
@property (nonatomic, assign) NSUInteger totalBytes;
62 64
@property (nonatomic, assign) NSUInteger currentBytes;
65
@property (nonatomic, assign) PithosAccount *pithosAccount;
63 66

  
64 67
@end
b/pithos-macos/PithosActivity.m
36 36
// or implied, of GRNET S.A.
37 37

  
38 38
#import "PithosActivity.h"
39
#import "PithosAccount.h"
39 40

  
40 41
@implementation PithosActivity
41
@synthesize type, message, totalBytes, currentBytes;
42
@synthesize type, message, totalBytes, currentBytes, pithosAccount;
42 43

  
43 44
#pragma mark -
44 45
#pragma mark Object Lifecycle
45 46

  
46
- (id)initWithType:(PithosActivityType)aType {
47
- (id)initWithType:(PithosActivityType)aType pithosAccount:(PithosAccount *)aPithosAccount {
47 48
    if ((self = [super init])) {
48 49
        type = aType;
49 50
        totalBytes = 0;
50 51
        currentBytes = 0;
52
        pithosAccount = aPithosAccount;
51 53
    }
52 54
    return self;
53 55
}
......
58 60
}
59 61

  
60 62
- (NSString *)description {
61
    return [NSString stringWithFormat:@"type: %lu, message: %@, totalBytes: %lu, currentBytes: %lu", 
62
            type, message, totalBytes, currentBytes];
63
    if (pithosAccount)
64
        return [NSString stringWithFormat:@"type: %lu, message: %@, totalBytes: %lu, currentBytes: %lu, pithosAccount: %@", 
65
                type, message, totalBytes, currentBytes, pithosAccount.name];
66
    else
67
        return [NSString stringWithFormat:@"type: %lu, message: %@, totalBytes: %lu, currentBytes: %lu", 
68
                type, message, totalBytes, currentBytes];
63 69
}
64 70

  
65 71
@end
b/pithos-macos/PithosActivityFacility.h
2 2
//  PithosActivityFacility.h
3 3
//  pithos-macos
4 4
//
5
// Copyright 2011 GRNET S.A. All rights reserved.
5
// Copyright 2011-2012 GRNET S.A. All rights reserved.
6 6
//
7 7
// Redistribution and use in source and binary forms, with or
8 8
// without modification, are permitted provided that the following
......
37 37

  
38 38
#import <Foundation/Foundation.h>
39 39
#import "PithosActivity.h"
40
@class PithosAccount;
40 41

  
41 42
@protocol PithosActivityFacilityDelegate <NSObject>
42 43
@required
......
62 63
+ (id)defaultPithosActivityFacility;
63 64

  
64 65
- (void)reset;
66

  
65 67
- (PithosActivity *)startActivityWithType:(PithosActivityType)type 
66 68
                                  message:(NSString *)message 
67 69
                               totalBytes:(NSUInteger)totalBytes 
68
                             currentBytes:(NSUInteger)currentBytes;
70
                             currentBytes:(NSUInteger)currentBytes 
71
                            pithosAccount:(PithosAccount *)pithosAccount;
69 72
- (PithosActivity *)startActivityWithType:(PithosActivityType)type 
70
                                  message:(NSString *)message;
73
                                  message:(NSString *)message 
74
                               totalBytes:(NSUInteger)totalBytes 
75
                             currentBytes:(NSUInteger)currentBytes;
76
- (PithosActivity *)startActivityWithType:(PithosActivityType)type message:(NSString *)message pithosAccount:(PithosAccount *)pithosAccount;
77
- (PithosActivity *)startActivityWithType:(PithosActivityType)type message:(NSString *)message;
78
- (PithosActivity *)startAndEndActivityWithType:(PithosActivityType)type message:(NSString *)message pithosAccount:(PithosAccount *)pithosAccount;
71 79
- (PithosActivity *)startAndEndActivityWithType:(PithosActivityType)type message:(NSString *)message;
80

  
72 81
- (void)updateActivity:(PithosActivity *)activity 
73 82
           withMessage:(NSString *)message 
74 83
            totalBytes:(NSUInteger)totalBytes 
b/pithos-macos/PithosActivityFacility.m
2 2
//  PithosActivityFacility.m
3 3
//  pithos-macos
4 4
//
5
// Copyright 2011 GRNET S.A. All rights reserved.
5
// Copyright 2011-2012 GRNET S.A. All rights reserved.
6 6
//
7 7
// Redistribution and use in source and binary forms, with or
8 8
// without modification, are permitted provided that the following
......
36 36
// or implied, of GRNET S.A.
37 37

  
38 38
#import "PithosActivityFacility.h"
39
#import "PithosAccount.h"
39 40

  
40 41
static PithosActivityFacility *defaultPithosActivityFacility = nil;
41 42

  
......
172 173
            }
173 174
            pickedRunning = YES;
174 175
        }
175
        if (activity && activity.message)
176
            [info setObject:activity.message forKey:@"message"];
176
        if (activity && activity.message) {
177
            if (activity.pithosAccount)
178
                [info setObject:[NSString stringWithFormat:@"[%@] %@", activity.pithosAccount.name, activity.message] forKey:@"message"];
179
            else
180
                [info setObject:activity.message forKey:@"message"];
181
        }
177 182
        [info setObject:[NSNumber numberWithUnsignedInteger:[runningActivities count]] forKey:@"runningActivitiesCount"];
178 183
        [info setObject:[NSNumber numberWithUnsignedInteger:[endingActivities count]] forKey:@"endingActivitiesCount"];
179 184
        [info setObject:[NSNumber numberWithUnsignedInteger:totalUploadBytes] forKey:@"totalUploadBytes"];
......
193 198
- (PithosActivity *)startActivityWithType:(PithosActivityType)type 
194 199
                                  message:(NSString *)message 
195 200
                               totalBytes:(NSUInteger)totalBytes 
196
                               currentBytes:(NSUInteger)currentBytes {
197
    PithosActivity *activity = [[[PithosActivity alloc] initWithType:type] autorelease];
201
                             currentBytes:(NSUInteger)currentBytes 
202
                            pithosAccount:(PithosAccount *)pithosAccount {
203
    PithosActivity *activity = [[[PithosActivity alloc] initWithType:type pithosAccount:pithosAccount] autorelease];
198 204
    activity.message = message;
199 205
    activity.totalBytes = totalBytes;
200 206
    activity.currentBytes = currentBytes;
......
226 232
}
227 233

  
228 234
- (PithosActivity *)startActivityWithType:(PithosActivityType)type 
235
                                  message:(NSString *)message 
236
                               totalBytes:(NSUInteger)totalBytes 
237
                             currentBytes:(NSUInteger)currentBytes {
238
    return [self startActivityWithType:type message:message totalBytes:totalBytes currentBytes:currentBytes pithosAccount:nil];
239
}
240

  
241
- (PithosActivity *)startActivityWithType:(PithosActivityType)type 
242
                                  message:(NSString *)message 
243
                            pithosAccount:(PithosAccount *)pithosAccount {
244
    return [self startActivityWithType:type message:message totalBytes:0 currentBytes:0 pithosAccount:pithosAccount];
245
}
246

  
247
- (PithosActivity *)startActivityWithType:(PithosActivityType)type 
229 248
                                  message:(NSString *)message {
230
    return [self startActivityWithType:type message:message totalBytes:0 currentBytes:0];
249
    return [self startActivityWithType:type message:message pithosAccount:nil];
231 250
}
232 251

  
233
- (PithosActivity *)startAndEndActivityWithType:(PithosActivityType)type message:(NSString *)message {
234
    PithosActivity *activity = [[[PithosActivity alloc] initWithType:type] autorelease];
252
- (PithosActivity *)startAndEndActivityWithType:(PithosActivityType)type 
253
                                        message:(NSString *)message 
254
                                  pithosAccount:(PithosAccount *)pithosAccount {
255
    PithosActivity *activity = [[[PithosActivity alloc] initWithType:type pithosAccount:pithosAccount] autorelease];
235 256
    activity.message = message;
236 257
    activity.totalBytes = 0;
237 258
    activity.currentBytes = 0;
......
243 264
    return activity;
244 265
}
245 266

  
267
- (PithosActivity *)startAndEndActivityWithType:(PithosActivityType)type message:(NSString *)message {
268
    return [self startAndEndActivityWithType:type message:message pithosAccount:nil];
269
}
270

  
246 271
- (void)updateActivity:(PithosActivity *)activity 
247 272
           withMessage:(NSString *)message 
248 273
            totalBytes:(NSUInteger)totalBytes 
b/pithos-macos/PithosBrowserController.h
47 47

  
48 48
@interface PithosBrowserController : NSWindowController <NSBrowserDelegate, NSSplitViewDelegate, NSOutlineViewDelegate, NSOutlineViewDataSource, NSMenuDelegate, PithosActivityFacilityDelegate> {
49 49
    BOOL browserInitialized;
50
    BOOL browserActive;
50 51
    
51 52
    ASIPithos *pithos;
52 53
    
......
87 88
    ASINetworkQueue *deleteNetworkQueue;
88 89
    ASINetworkQueue *uploadNetworkQueue;
89 90
    ASINetworkQueue *downloadNetworkQueue;
90
    dispatch_queue_t moveQueue;
91
    dispatch_queue_t copyQueue;
92
    dispatch_queue_t deleteQueue;
93
    dispatch_queue_t uploadQueue;
94
    dispatch_queue_t downloadQueue;
91
    NSOperationQueue *moveQueue;
92
    NSOperationQueue *copyQueue;
93
    NSOperationQueue *deleteQueue;
94
    NSOperationQueue *uploadQueue;
95
    NSOperationQueue *downloadQueue;
96
    NSOperationQueue *moveCallbackQueue;
97
    NSOperationQueue *copyCallbackQueue;
98
    NSOperationQueue *deleteCallbackQueue;
99
    NSOperationQueue *uploadCallbackQueue;
100
    NSOperationQueue *downloadCallbackQueue;
95 101
}
96 102

  
97 103
@property (nonatomic, retain) ASIPithos *pithos;
......
119 125

  
120 126
- (IBAction)forceRefresh:(id)sender;
121 127
- (IBAction)refresh:(id)sender;
128
- (void)resetBrowser;
129
- (void)startBrowser;
130
- (BOOL)operationsPending;
122 131

  
123 132
@end
b/pithos-macos/PithosBrowserController.m
120 120
    return [super initWithWindowNibName:@"PithosBrowserController"];
121 121
}
122 122

  
123
- (void)dealloc {
124
    [[NSNotificationCenter defaultCenter] removeObserver:self];
125
    dispatch_release(moveQueue);
126
    dispatch_release(copyQueue);
127
    dispatch_release(deleteQueue);
128
    dispatch_release(uploadQueue);
129
    dispatch_release(downloadQueue);
130
    [moveNetworkQueue cancelAllOperations];
131
    [moveNetworkQueue release];
132
    [copyNetworkQueue cancelAllOperations];
133
    [copyNetworkQueue release];
134
    [deleteNetworkQueue cancelAllOperations];
135
    [deleteNetworkQueue release];
136
    [uploadNetworkQueue cancelAllOperations];
137
    [uploadNetworkQueue release];
138
    [downloadNetworkQueue cancelAllOperations];
139
    [downloadNetworkQueue release];
140
    [refreshTimer invalidate];
141
    [refreshTimer release];
142
    [clipboardParentNode release];
143
    [clipboardNodes release];
144
    [draggedParentNode release];
145
    [draggedNodes release];
146
    [sharedPreviewController release];
147
    [othersSharedNode release];
148
    [mySharedNode release];
149
    [sharedNode release];
150
    [containersNodeChildren release];
151
    [containersNode release];
152
    [accountNode release];
153
    [rootNode release];
154
    [pithos release];
155
    [super dealloc];
123
- (void)windowDidLoad {
124
    [super windowDidLoad];
125
    if (browser && !browserInitialized) {
126
        browserInitialized = YES;
127
        [self initBrowser];
128
    }
156 129
}
157 130

  
158 131
- (void)initBrowser {
......
172 145
    
173 146
    moveNetworkQueue = [[ASINetworkQueue alloc] init];
174 147
    moveNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
175
    [moveNetworkQueue go];
148
//    moveNetworkQueue.maxConcurrentOperationCount = 1;
176 149
    copyNetworkQueue = [[ASINetworkQueue alloc] init];
177 150
    copyNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
178
    [copyNetworkQueue go];
151
//    copyNetworkQueue.maxConcurrentOperationCount = 1;
179 152
    deleteNetworkQueue = [[ASINetworkQueue alloc] init];
180 153
    deleteNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
181
    [deleteNetworkQueue go];
154
//    deleteNetworkQueue.maxConcurrentOperationCount = 1;
182 155
    uploadNetworkQueue = [[ASINetworkQueue alloc] init];
183 156
    uploadNetworkQueue.showAccurateProgress = YES;
184 157
    uploadNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
185
    [uploadNetworkQueue go];
158
//    uploadNetworkQueue.maxConcurrentOperationCount = 1;
186 159
    downloadNetworkQueue = [[ASINetworkQueue alloc] init];
187 160
    downloadNetworkQueue.showAccurateProgress = YES;
188 161
    downloadNetworkQueue.shouldCancelAllRequestsOnFailure = NO;
189
    [downloadNetworkQueue go];
162
//    downloadNetworkQueue.maxConcurrentOperationCount = 1;
163
    
164
    moveQueue = [[NSOperationQueue alloc] init];
165
    [moveQueue setSuspended:YES];
166
    moveQueue.name = @"gr.grnet.pithos.MoveQueue";
167
//    moveQueue.maxConcurrentOperationCount = 1;
168
    copyQueue = [[NSOperationQueue alloc] init];
169
    [copyQueue setSuspended:YES];
170
    copyQueue.name = @"gr.grnet.pithos.CopyQueue";
171
//    copyQueue.maxConcurrentOperationCount = 1;
172
    deleteQueue = [[NSOperationQueue alloc] init];
173
    [deleteQueue setSuspended:YES];
174
    deleteQueue.name = @"gr.grnet.pithos.DeleteQueue";
175
//    deleteQueue.maxConcurrentOperationCount = 1;
176
    uploadQueue = [[NSOperationQueue alloc] init];
177
    [uploadQueue setSuspended:YES];
178
    uploadQueue.name = @"gr.grnet.pithos.UploadQueue";
179
//    uploadQueue.maxConcurrentOperationCount = 1;
180
    downloadQueue = [[NSOperationQueue alloc] init];
181
    [downloadQueue setSuspended:YES];
182
    downloadQueue.name = @"gr.grnet.pithos.DownloadQueue";
183
//    downloadQueue.maxConcurrentOperationCount = 1;
190 184
    
191
    moveQueue = dispatch_queue_create("gr.grnet.pithos.MoveQueue", NULL);
192
    copyQueue = dispatch_queue_create("gr.grnet.pithos.CopyQueue", NULL);
193
    deleteQueue = dispatch_queue_create("gr.grnet.pithos.DeleteQueue", NULL);
194
    uploadQueue = dispatch_queue_create("gr.grnet.pithos.UploadQueue", NULL);
195
    downloadQueue = dispatch_queue_create("gr.grnet.pithos.DownloadQueue", NULL);
185
    moveCallbackQueue = [[NSOperationQueue alloc] init];
186
    [moveCallbackQueue setSuspended:YES];
187
    moveCallbackQueue.name = @"gr.grnet.pithos.MoveCallbackQueue";
188
//    moveCallbackQueue.maxConcurrentOperationCount = 1;
189
    copyCallbackQueue = [[NSOperationQueue alloc] init];
190
    [copyCallbackQueue setSuspended:YES];
191
    copyCallbackQueue.name = @"gr.grnet.pithos.CopyCallbackQueue";
192
//    copyCallbackQueue.maxConcurrentOperationCount = 1;
193
    deleteCallbackQueue = [[NSOperationQueue alloc] init];
194
    [deleteCallbackQueue setSuspended:YES];
195
    deleteCallbackQueue.name = @"gr.grnet.pithos.DeleteCallbackQueue";
196
//    deleteCallbackQueue.maxConcurrentOperationCount = 1;
197
    uploadCallbackQueue = [[NSOperationQueue alloc] init];
198
    [uploadCallbackQueue setSuspended:YES];
199
    uploadCallbackQueue.name = @"gr.grnet.pithos.UploadCallbackQueue";
200
//    uploadCallbackQueue.maxConcurrentOperationCount = 1;
201
    downloadCallbackQueue = [[NSOperationQueue alloc] init];
202
    [downloadCallbackQueue setSuspended:YES];
203
    downloadCallbackQueue.name = @"gr.grnet.pithos.DownloadCallbackQueue";
204
//    downloadCallbackQueue.maxConcurrentOperationCount = 1;
196 205
    
197 206
    [activityProgressIndicator setUsesThreadedAnimation:YES];
198 207
    [activityProgressIndicator setMinValue:0.0];
......
247 256
}
248 257

  
249 258
- (void)resetBrowser {
259
    @synchronized(self) {
260
        if (!browserActive)
261
            return;
262
    }
263

  
250 264
    [refreshTimer invalidate];
251 265
    [refreshTimer release];
252 266
    
253
    [moveNetworkQueue cancelAllOperations];
254
    [copyNetworkQueue cancelAllOperations];
255
    [deleteNetworkQueue cancelAllOperations];
256
    [uploadNetworkQueue cancelAllOperations];
257
    [downloadNetworkQueue cancelAllOperations];
267
    [moveNetworkQueue reset];
268
    [copyNetworkQueue reset];
269
    [deleteNetworkQueue reset];
270
    [uploadNetworkQueue reset];
271
    [downloadNetworkQueue reset];
258 272
    
273
    [moveQueue cancelAllOperations];
274
    [moveQueue setSuspended:YES];
275
    [copyQueue cancelAllOperations];
276
    [copyQueue setSuspended:YES];
277
    [deleteQueue cancelAllOperations];
278
    [deleteQueue setSuspended:YES];
279
    [uploadQueue cancelAllOperations];
280
    [uploadQueue setSuspended:YES];
281
    [downloadQueue cancelAllOperations];
282
    [downloadQueue setSuspended:YES];
283

  
284
    [moveCallbackQueue cancelAllOperations];
285
    [moveCallbackQueue setSuspended:YES];
286
    [copyCallbackQueue cancelAllOperations];
287
    [copyCallbackQueue setSuspended:YES];
288
    [deleteCallbackQueue cancelAllOperations];
289
    [deleteCallbackQueue setSuspended:YES];
290
    [uploadCallbackQueue cancelAllOperations];
291
    [uploadCallbackQueue setSuspended:YES];
292
    [downloadCallbackQueue cancelAllOperations];
293
    [downloadCallbackQueue setSuspended:YES];
294

  
259 295
    rootNode = nil;
260 296
    [browser loadColumnZero];
261 297
    [containersNodeChildren removeAllObjects];
262 298
    [outlineView reloadData];
263
	// Expand the folder outline view
299
    // Expand the folder outline view
264 300
    [outlineView expandItem:nil expandChildren:YES];
265
	[outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
301
    [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
266 302
    
267 303
    activityFacility.delegate = nil;
268 304
    [activityProgressIndicator setDoubleValue:1.0];
269 305
    [activityProgressIndicator stopAnimation:self];
306
    
307
    @synchronized(self) {
308
        browserActive = NO;
309
    }
270 310
}
271 311

  
272 312
- (void)startBrowser {
313
    @synchronized(self) {
314
        if (browserActive)
315
            return;
316
    }
317
    
318
    // In the improbable case of leftover operations
319
    [moveNetworkQueue reset];
320
    [copyNetworkQueue reset];
321
    [deleteNetworkQueue reset];
322
    [uploadNetworkQueue reset];
323
    [downloadNetworkQueue reset];
324
    [moveQueue cancelAllOperations];
325
    [copyQueue cancelAllOperations];
326
    [deleteQueue cancelAllOperations];
327
    [uploadQueue cancelAllOperations];
328
    [downloadQueue cancelAllOperations];
329
    [moveCallbackQueue cancelAllOperations];
330
    [copyCallbackQueue cancelAllOperations];
331
    [deleteCallbackQueue cancelAllOperations];
332
    [uploadCallbackQueue cancelAllOperations];
333
    [downloadCallbackQueue cancelAllOperations];
334

  
335
    [moveNetworkQueue go];
336
    [copyNetworkQueue go];
337
    [deleteNetworkQueue go];
338
    [uploadNetworkQueue go];
339
    [downloadNetworkQueue go];
340
    [moveQueue setSuspended:NO];
341
    [copyQueue setSuspended:NO];
342
    [deleteQueue setSuspended:NO];
343
    [uploadQueue setSuspended:NO];
344
    [downloadQueue setSuspended:NO];
345
    [moveCallbackQueue setSuspended:NO];
346
    [copyCallbackQueue setSuspended:NO];
347
    [deleteCallbackQueue setSuspended:NO];
348
    [uploadCallbackQueue setSuspended:NO];
349
    [downloadCallbackQueue setSuspended:NO];
350

  
273 351
    accountNode.pithos = pithos;
274
    [accountNode refresh];
352
    [accountNode forceRefresh];
275 353
    mySharedNode.pithos = pithos;
276
    [mySharedNode refresh];
354
    [mySharedNode forceRefresh];
277 355
    othersSharedNode.pithos = pithos;
278
    [othersSharedNode refresh];
279
    
280
    [activityFacility reset];
356
    [othersSharedNode forceRefresh];
357
            
358
//    [activityFacility reset];
281 359
    activityFacility.delegate = self;
282
    
283
    refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:30 target:self selector:@selector(forceRefresh:) userInfo:self repeats:YES] retain];
360
            
361
    refreshTimer = [[NSTimer scheduledTimerWithTimeInterval:30 
362
                                                     target:self 
363
                                                   selector:@selector(forceRefresh:) 
364
                                                   userInfo:self 
365
                                                    repeats:YES] retain];
366
    @synchronized(self) {
367
        browserActive = YES;
368
    }
284 369
}
285 370

  
286
- (void)setPithos:(ASIPithos *)aPithos {
287
    if (aPithos && [aPithos isNotEqualTo:pithos]) {
288
        [self resetBrowser];
289
        [pithos release];
290
        pithos = [aPithos retain];
291
        [self startBrowser];
292
    }
371
- (BOOL)operationsPending {
372
    return ([moveNetworkQueue operationCount] || 
373
            [copyNetworkQueue operationCount] || 
374
            [deleteNetworkQueue operationCount] || 
375
            [uploadNetworkQueue operationCount] || 
376
            [downloadNetworkQueue operationCount] || 
377
            [moveQueue operationCount] || 
378
            [copyQueue operationCount] || 
379
            [deleteQueue operationCount] || 
380
            [uploadQueue operationCount] || 
381
            [downloadQueue operationCount] || 
382
            [moveCallbackQueue operationCount] || 
383
            [copyCallbackQueue operationCount] || 
384
            [deleteCallbackQueue operationCount] || 
385
            [uploadCallbackQueue operationCount] || 
386
            [downloadCallbackQueue operationCount]);
293 387
}
294 388

  
295
- (void)windowDidLoad {
296
    [super windowDidLoad];
297
    if (browser && !browserInitialized) {
298
        browserInitialized = YES;
299
        [self initBrowser];
389
- (void)dealloc {
390
    [[NSNotificationCenter defaultCenter] removeObserver:self];
391
    [self resetBrowser];
392
    [moveQueue release];
393
    [copyQueue release];
394
    [deleteQueue release];
395
    [uploadQueue release];
396
    [downloadQueue release];
397
    [moveNetworkQueue release];
398
    [copyNetworkQueue release];
399
    [deleteNetworkQueue release];
400
    [uploadNetworkQueue release];
401
    [downloadNetworkQueue release];
402
    [clipboardParentNode release];
403
    [clipboardNodes release];
404
    [draggedParentNode release];
405
    [draggedNodes release];
406
    [sharedPreviewController release];
407
    [othersSharedNode release];
408
    [mySharedNode release];
409
    [sharedNode release];
410
    [containersNodeChildren release];
411
    [containersNode release];
412
    [accountNode release];
413
    [rootNode release];
414
    [pithos release];
415
    [super dealloc];
416
}
417

  
418
- (void)setPithos:(ASIPithos *)aPithos {
419
    if (aPithos) {
420
        if (![aPithos.authUser isEqualToString:pithos.authUser] || 
421
            ![aPithos.authToken isEqualToString:pithos.authToken] || 
422
            ![aPithos.storageURLPrefix isEqualToString:pithos.storageURLPrefix] ||
423
            ![aPithos.publicURLPrefix isEqualToString:pithos.publicURLPrefix]) {
424
            [self resetBrowser];
425
            [pithos release];
426
            pithos = [aPithos retain];
427
            [self startBrowser];
428
        } else {
429
            [self startBrowser];
430
        }
300 431
    }
301 432
}
302 433

  
434

  
303 435
#pragma mark -
304 436
#pragma mark Observers
305 437

  
......
347 479
        // Create pithos node
348 480
        ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithPithos:pithos 
349 481
                                                                                                            containerName:@"pithos"];
350
        [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
351
        while (![containerRequest isFinished]) {
352
            usleep(1);
353
        }
482
        ASINetworkQueue *networkQueue = [ASINetworkQueue queue];
483
        [networkQueue go];
484
        [networkQueue addOperations:[NSArray arrayWithObject:[PithosUtilities prepareRequest:containerRequest]] waitUntilFinished:YES];
354 485
        if ([containerRequest error]) {
355
            [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
486
            dispatch_async(dispatch_get_main_queue(), ^{
487
                [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
488
            });
356 489
        } else {
357 490
            refreshAccountNode = YES;
358 491
        }
......
361 494
        // Create trash node
362 495
        ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithPithos:pithos 
363 496
                                                                                                            containerName:@"trash"];
364
        [[PithosUtilities prepareRequest:containerRequest priority:NSOperationQueuePriorityVeryHigh] startAsynchronous];
365
        while (![containerRequest isFinished]) {
366
            usleep(1);
367
        }
497
        ASINetworkQueue *networkQueue = [ASINetworkQueue queue];
498
        [networkQueue go];
499
        [networkQueue addOperations:[NSArray arrayWithObject:[PithosUtilities prepareRequest:containerRequest]] waitUntilFinished:YES];
368 500
        if ([containerRequest error]) {
369
            [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
501
            dispatch_async(dispatch_get_main_queue(), ^{
502
                [PithosUtilities httpRequestErrorAlertWithRequest:containerRequest];
503
            });
370 504
        } else {
371 505
            refreshAccountNode = YES;
372 506
        }
......
380 514
    // Expand the folder outline view
381 515
    [outlineView expandItem:nil expandChildren:YES];
382 516
    
383
    if ((rootNode == nil) || (rootNode == containersNode) || (rootNode == sharedNode)) {
517
    if (((rootNode == nil) || (rootNode == containersNode) || (rootNode == sharedNode)) && [containersNodeChildren count]) {
384 518
        rootNode = [containersNodeChildren objectAtIndex:0];
385 519
        [browser loadColumnZero];
386 520
    }
......
489 623
    }
490 624
    if (([node class] == [PithosObjectNode class]) || 
491 625
        (([node class] == [PithosSubdirNode class]) && !node.pithosObject.subdir && [node.pithosObject.name hasSuffix:@"/"])) {
492
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
626
        // Operation: Rename (move) an object or subdir/ node
627
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
493 628
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
629
            if (operation.isCancelled) {
630
                [pool drain];
631
                return;
632
            }
494 633
            NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
495 634
            if ([newName hasSuffix:@"/"])
496 635
                destinationObjectName = [destinationObjectName stringByAppendingString:@"/"];
......
502 641
                                                error:&error 
503 642
                                          isDirectory:&isDirectory 
504 643
                                       sharingAccount:nil]) {
505
                NSAlert *alert = [[[NSAlert alloc] init] autorelease];
506
                [alert setMessageText:@"Name Taken"];
507
                [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
508
                [alert addButtonWithTitle:@"OK"];
509
                [alert runModal];
644
                dispatch_async(dispatch_get_main_queue(), ^{
645
                    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
646
                    [alert setMessageText:@"Name Taken"];
647
                    [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
648
                    [alert addButtonWithTitle:@"OK"];
649
                    [alert runModal];
650
                });
510 651
                [pool drain];
511 652
                return;
512 653
            } else if (error) {
513 654
                [pool drain];
514 655
                return;
515 656
            }
657
            if (operation.isCancelled) {
658
                [pool drain];
659
                return;
660
            }
516 661
            ASIPithosObjectRequest *objectRequest = [PithosUtilities moveObjectRequestWithPithos:pithos 
517 662
                                                                                   containerName:node.pithosContainer.name 
518 663
                                                                                      objectName:node.pithosObject.name 
519 664
                                                                        destinationContainerName:node.pithosContainer.name 
520 665
                                                                           destinationObjectName:destinationObjectName 
521 666
                                                                                   checkIfExists:NO];
522
            if (objectRequest) {
667
            if (!operation.isCancelled && objectRequest) {
523 668
                objectRequest.delegate = self;
524 669
                objectRequest.didFinishSelector = @selector(performRequestFinishedDelegateInBackground:);
525 670
                objectRequest.didFailSelector = @selector(performRequestFailedDelegateInBackground:);
......
543 688
                  NSStringFromSelector(@selector(moveFinished:)), @"didFinishSelector", 
544 689
                  NSStringFromSelector(@selector(requestFailed:)), @"didFailSelector", 
545 690
                  moveNetworkQueue, @"networkQueue", 
546
                  @"moveQueue", @"queueType", 
691
                  @"move", @"operationType", 
547 692
                  nil]];
548 693
                [moveNetworkQueue addOperation:[PithosUtilities prepareRequest:objectRequest priority:NSOperationQueuePriorityHigh]];
549 694
            }
550 695
            [pool drain];
551
        });
696
        }];
697
        [moveQueue addOperation:operation];
552 698
    } else if ([node class] == [PithosSubdirNode class]) {
553 699
        if (firstSlashRange.length == 1)
554 700
            return;
555
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
701
        // Operation: Rename (move) a subdir node and its descendants
702
        // The resulting ASIPithosObjectRequests are chained through dependencies
703
        __block NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
556 704
            NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
705
            if (operation.isCancelled) {
706
                [pool drain];
707
                return;
708
            }
557 709
            NSString *destinationObjectName = [[node.pithosObject.name stringByDeletingLastPathComponent] stringByAppendingPathComponent:newName];
558 710
            NSError *error = nil;
559 711
            BOOL isDirectory;
......
563 715
                                                error:&error 
564 716
                                          isDirectory:&isDirectory 
565 717
                                       sharingAccount:nil]) {
566
                NSAlert *alert = [[[NSAlert alloc] init] autorelease];
567
                [alert setMessageText:@"Name Taken"];
568
                [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
569
                [alert addButtonWithTitle:@"OK"];
570
                [alert runModal];
718
                dispatch_async(dispatch_get_main_queue(), ^{
719
                    NSAlert *alert = [[[NSAlert alloc] init] autorelease];
720
                    [alert setMessageText:@"Name Taken"];
721
                    [alert setInformativeText:[NSString stringWithFormat:@"The name '%@' is already taken. Please choose a different name", newName]];
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff