Revision e8dc9335

b/pithos-macos/PithosAccount.h
39 39
@class PithosSyncDaemon;
40 40
@class ASIPithos;
41 41
@class PithosAccountNode;
42
@class PithosSharingAccountsNode;
42 43

  
43 44
@interface PithosAccount : NSObject <NSCoding> {
44 45
    NSString *uniqueName;
......
47 48
    
48 49
    BOOL syncActive;
49 50
    NSString *syncDirectoryPath;
50
    NSMutableDictionary *syncContainersDictionary;
51
    NSMutableDictionary *syncAccountsDictionary;
51 52
    NSDate *syncLastCompleted;
52 53
    PithosSyncDaemon *syncDaemon;
53 54
        
......
72 73
    
73 74
    ASIPithos *pithos;
74 75
    PithosAccountNode *accountNode;
76
    PithosSharingAccountsNode *sharingAccountsNode;
75 77
    
76 78
    BOOL updatePithos;
77 79
    BOOL resetSyncDaemonLocalState;
......
83 85

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

  
......
101 103

  
102 104
@property (readonly) ASIPithos *pithos;
103 105
@property (readonly) PithosAccountNode *accountNode;
106
@property (readonly) PithosSharingAccountsNode *sharingAccountsNode;
104 107

  
105 108
+ (id)pithosAccount;
106 109

  
......
109 112
- (void)loginWithServerURL:(NSString *)aServerURL;
110 113
- (void)updateSyncWithSyncActive:(BOOL)aSyncActive 
111 114
               syncDirectoryPath:(NSString *)aSyncDirectoryPath 
112
        syncContainersDictionary:(NSMutableDictionary *)aSyncContainersDictionary;
115
          syncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary;
113 116

  
114 117
@end
b/pithos-macos/PithosAccount.m
39 39
#import "PithosSyncDaemon.h"
40 40
#import "ASIPithos.h"
41 41
#import "PithosAccountNode.h"
42
#import "PithosSharingAccountsNode.h"
42 43
#import "pithos_macosAppDelegate.h"
43 44

  
44 45
@interface PithosAccount (Internal)
......
47 48

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

  
55 56
#pragma mark -
56 57
#pragma mark Object Lifecycle
......
64 65
}
65 66

  
66 67
- (void)dealloc {
68
    [sharingAccountsNode release];
67 69
    [accountNode release];
68 70
    [pithos release];
69 71
    [publicURLPrefix release];
......
78 80
    [serverURL release];
79 81
    [syncDaemon release];
80 82
    [syncLastCompleted release];
81
    [syncContainersDictionary release];
83
    [syncAccountsDictionary release];
82 84
    [syncDirectoryPath release];
83 85
    [name release];
84 86
    [uniqueName release];
......
86 88
}
87 89

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

  
93 95
#pragma mark -
......
173 175
    }
174 176
}
175 177

  
176
- (NSMutableDictionary *)syncContainersDictionary {
177
    if (!syncContainersDictionary) {
178
        syncContainersDictionary = [[NSMutableDictionary dictionaryWithObject:[NSMutableArray array] 
179
                                                                       forKey:@"pithos"] retain];
178
- (NSMutableDictionary *)syncAccountsDictionary {
179
    if (!syncAccountsDictionary) {
180
        syncAccountsDictionary = [[NSMutableDictionary dictionaryWithObject:[NSMutableDictionary dictionaryWithObject:[NSMutableArray array] 
181
                                                                                                               forKey:@"pithos"] 
182
                                                                     forKey:@""] retain];
180 183
    }        
181
    return syncContainersDictionary;
184
    return syncAccountsDictionary;
182 185
}
183 186

  
184
- (void)setSyncContainersDictionary:(NSMutableDictionary *)aSyncContainersDictionary {
185
    if (aSyncContainersDictionary && ![self.syncContainersDictionary isEqualToDictionary:aSyncContainersDictionary]) {
186
        [syncContainersDictionary release];
187
        syncContainersDictionary = [aSyncContainersDictionary retain];
187
- (void)setSyncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary {
188
    if (aSyncAccountsDictionary && ![self.syncAccountsDictionary isEqualToDictionary:aSyncAccountsDictionary]) {
189
        [syncAccountsDictionary release];
190
        syncAccountsDictionary = [aSyncAccountsDictionary retain];
188 191
        // XXX maybe check also here the validity of the dictionary? 
189 192
        
190 193
        @synchronized(self) {
......
208 211
        if (self.syncActive && !syncDaemon)
209 212
            syncDaemon = [[PithosSyncDaemon alloc] initWithDirectoryPath:self.syncDirectoryPath 
210 213
                                                           pithosAccount:self
211
                                                    containersDictionary:self.syncContainersDictionary
214
                                                      accountsDictionary:self.syncAccountsDictionary
212 215
                                                         resetLocalState:resetSyncDaemonLocalState];
213 216
        resetSyncDaemonLocalState = NO;
214 217
    }
......
359 362
                if (active)
360 363
                    [accountNode refreshInfo];
361 364
            }
365
            if (sharingAccountsNode && ![sharingAccountsNode.pithos isEqualTo:pithos])
366
                sharingAccountsNode.pithos = pithos;
362 367
            
363 368
            updatePithos = NO;
364 369
        }
......
375 380
    return accountNode;
376 381
}
377 382

  
383
- (PithosSharingAccountsNode *)sharingAccountsNode {
384
    if (!sharingAccountsNode) {
385
        sharingAccountsNode = [[PithosSharingAccountsNode alloc] initWithPithos:self.pithos];
386
        sharingAccountsNode.childrenUpdatedNotificationName = nil;
387
        sharingAccountsNode.inheritChildrenUpdatedNotificationName = YES;
388
    }
389
    return sharingAccountsNode;
390
}
391

  
378 392
#pragma mark -
379 393
#pragma mark Actions
380 394

  
......
408 422

  
409 423
- (void)updateSyncWithSyncActive:(BOOL)aSyncActive 
410 424
               syncDirectoryPath:(NSString *)aSyncDirectoryPath 
411
        syncContainersDictionary:(NSMutableDictionary *)aSyncContainersDictionary {
412
    self.syncContainersDictionary = aSyncContainersDictionary;
425
          syncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary {
426
    self.syncAccountsDictionary = aSyncAccountsDictionary;
413 427
    self.syncDirectoryPath = aSyncDirectoryPath;
414 428
    self.syncActive = aSyncActive;
415 429
    if (syncDaemon) {
416
        self.syncDaemon.containersDictionary = self.syncContainersDictionary;
430
        self.syncDaemon.accountsDictionary = self.syncAccountsDictionary;
417 431
        self.syncDaemon.directoryPath = self.syncDirectoryPath;
418 432
        if (self.syncActive)
419 433
            [self.syncDaemon startDaemon];
......
431 445

  
432 446
        self.syncActive = [decoder decodeBoolForKey:@"syncActive"];
433 447
        self.syncDirectoryPath = [decoder decodeObjectForKey:@"syncDirectoryPath"];
434
        NSDictionary *immutableContainersDictionary = [decoder decodeObjectForKey:@"syncContainersDictionary"];
435
        syncContainersDictionary = [[NSMutableDictionary alloc] initWithCapacity:[immutableContainersDictionary count]];
436
        for (NSString *containerName in immutableContainersDictionary) {
437
            [syncContainersDictionary setObject:[NSMutableArray arrayWithArray:[immutableContainersDictionary objectForKey:containerName]] 
438
                                         forKey:containerName];
448
        NSDictionary *immutableAccountsDictionary = [decoder decodeObjectForKey:@"syncAccountsDictionary"];
449
        syncAccountsDictionary = [[NSMutableDictionary alloc] initWithCapacity:[immutableAccountsDictionary count]];
450
        for (NSString *accountName in immutableAccountsDictionary) {
451
            NSDictionary *immutableContainersDictionary = [immutableAccountsDictionary objectForKey:accountName];
452
            NSMutableDictionary *syncContainersDictionary = [NSMutableDictionary dictionary];
453
            for (NSString *containerName in [immutableAccountsDictionary objectForKey:accountName]) {
454
                [syncContainersDictionary setObject:[NSMutableArray arrayWithArray:[immutableContainersDictionary objectForKey:containerName]] 
455
                                             forKey:containerName];
456
            }
457
            if ([syncContainersDictionary count])
458
                [syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName];
439 459
        }
440 460
        self.syncLastCompleted = [decoder decodeObjectForKey:@"syncLastCompleted"];
441 461
        
......
466 486
    
467 487
    [encoder encodeBool:syncActive forKey:@"syncActive"];
468 488
    [encoder encodeObject:syncDirectoryPath forKey:@"syncDirectoryPath"];
469
    [encoder encodeObject:syncContainersDictionary forKey:@"syncContainersDictionary"];
489
    [encoder encodeObject:syncAccountsDictionary forKey:@"syncAccountsDictionary"];
470 490
    [encoder encodeObject:self.syncLastCompleted forKey:@"syncLastCompleted"];
471 491

  
472 492
    [encoder encodeObject:serverURL forKey:@"serverURL"];
b/pithos-macos/PithosPreferencesController.h
37 37

  
38 38
#import <Cocoa/Cocoa.h>
39 39
@class PithosAccount;
40
@class PithosEmptyNode;
40 41

  
41 42
@interface PithosPreferencesController : NSWindowController <NSWindowDelegate, NSOutlineViewDataSource> {
42 43
    PithosAccount *selectedPithosAccount;
......
54 55
    
55 56
    BOOL syncActive;
56 57
    NSString *syncDirectoryPath;
57
    NSMutableDictionary *syncContainersDictionary;
58
    NSMutableDictionary *syncAccountsDictionary;
58 59
    BOOL syncApplyEnable;
59 60
    BOOL syncCancelEnable;
60
    NSOutlineView *syncContainersOutlineView;
61
    NSMutableDictionary *syncContainersRootFilesNodes;
61
    NSOutlineView *syncAccountsOutlineView;
62
    PithosEmptyNode *syncAccountsMyAccountNode;
63
    NSMutableDictionary *syncAccountsRootFilesNodes;
62 64
    
63 65
    NSDictionaryController *groupsDictionaryController;
64 66
    NSDictionaryController *selectedGroupMembersDictionaryController;
......
79 81

  
80 82
@property (nonatomic, assign) BOOL syncActive;
81 83
@property (nonatomic, copy) NSString *syncDirectoryPath;
82
@property (nonatomic, copy) NSMutableDictionary *syncContainersDictionary;
84
@property (nonatomic, copy) NSMutableDictionary *syncAccountsDictionary;
83 85
@property (nonatomic, assign) BOOL syncApplyEnable;
84 86
@property (nonatomic, assign) BOOL syncCancelEnable;
85
@property (nonatomic, assign) IBOutlet NSOutlineView *syncContainersOutlineView;
86
@property (nonatomic, retain) NSMutableDictionary *syncContainersRootFilesNodes;
87
@property (nonatomic, assign) IBOutlet NSOutlineView *syncAccountsOutlineView;
88
@property (nonatomic, retain) NSMutableDictionary *syncAccountsRootFilesNodes;
87 89

  
88 90
@property (nonatomic, assign) IBOutlet NSDictionaryController *groupsDictionaryController;
89 91
@property (nonatomic, assign) IBOutlet NSDictionaryController *selectedGroupMembersDictionaryController;
b/pithos-macos/PithosPreferencesController.m
38 38
#import "PithosPreferencesController.h"
39 39
#import "PithosBrowserController.h"
40 40
#import "PithosAccountNode.h"
41
#import "PithosSharingAccountsNode.h"
41 42
#import "PithosContainerNode.h"
42 43
#import "PithosSubdirNode.h"
43 44
#import "PithosObjectNode.h"
......
69 70
@synthesize accountsArrayController;
70 71
@synthesize accountRemoveEnable;
71 72
@synthesize serverURL, authUser, authToken, manual, loginEnable, loginCancelEnable;
72
@synthesize syncActive, syncDirectoryPath, syncContainersDictionary, syncApplyEnable, syncCancelEnable, 
73
            syncContainersOutlineView, syncContainersRootFilesNodes;
73
@synthesize syncActive, syncDirectoryPath, syncAccountsDictionary, syncApplyEnable, syncCancelEnable, 
74
            syncAccountsOutlineView, syncAccountsRootFilesNodes;
74 75
@synthesize groupsDictionaryController, selectedGroupMembersDictionaryController;
75 76

  
76 77
#pragma mark -
......
90 91
//	// Select the first tab when the window is loaded for the first time.
91 92
//	[[window valueForKeyPath:@"toolbar"] setSelectedItemIdentifier:@"0"];
92 93
    
93
    [[[syncContainersOutlineView tableColumns] objectAtIndex:1] setDataCell:[[[PithosPreferencesSyncOutlineViewCell alloc] init] autorelease]];
94
    [[[syncAccountsOutlineView tableColumns] objectAtIndex:1] setDataCell:[[[PithosPreferencesSyncOutlineViewCell alloc] init] autorelease]];
95
    syncAccountsMyAccountNode = [[PithosEmptyNode alloc] initWithDisplayName:@"<my account>" 
96
                                                                        icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)]];
94 97
    
95 98
    [groupsDictionaryController setInitialKey:@"group"];
96 99
    [groupsDictionaryController setInitialValue:@"user"];
......
129 132
}
130 133

  
131 134
- (void)selectedPithosAccountNodeChildrenUpdated:(NSNotification *)notification {
132
    [syncContainersOutlineView reloadData];
133
    [syncContainersOutlineView expandItem:nil expandChildren:YES];
135
    [syncAccountsOutlineView reloadData];
136
    [syncAccountsOutlineView expandItem:nil expandChildren:YES];
134 137
}
135 138

  
136 139
#pragma mark -
......
155 158
                             (![selectedPithosAccount.syncDirectoryPath isEqualToString:syncDirectoryPath] && 
156 159
                              (![[NSFileManager defaultManager] fileExistsAtPath:syncDirectoryPath isDirectory:&isDirectory] || 
157 160
                               isDirectory)) ||
158
                             ![selectedPithosAccount.syncContainersDictionary isEqualToDictionary:syncContainersDictionary]));
161
                             ![selectedPithosAccount.syncAccountsDictionary isEqualToDictionary:syncAccountsDictionary]));
159 162
    self.syncCancelEnable = (selectedPithosAccount.active && 
160 163
                             ((selectedPithosAccount.syncActive != syncActive) || 
161 164
                              ![selectedPithosAccount.syncDirectoryPath isEqualToString:syncDirectoryPath] ||
162
                              ![selectedPithosAccount.syncContainersDictionary isEqualToDictionary:syncContainersDictionary]));
165
                              ![selectedPithosAccount.syncAccountsDictionary isEqualToDictionary:syncAccountsDictionary]));
163 166
}
164 167

  
165 168
#pragma mark -
......
168 171
- (void)setSelectedPithosAccount:(PithosAccount *)aSelectedPithosAccount {
169 172
    if (aSelectedPithosAccount && ![aSelectedPithosAccount isEqualTo:selectedPithosAccount]) {
170 173
        selectedPithosAccount.accountNode.childrenUpdatedNotificationName = nil;
174
        selectedPithosAccount.sharingAccountsNode.childrenUpdatedNotificationName = nil;
171 175
        [selectedPithosAccount release];
172 176
        selectedPithosAccount = [aSelectedPithosAccount retain];
173
        selectedPithosAccount.accountNode.childrenUpdatedNotificationName = [NSString stringWithString:@"SelectedPithosAccountNodeChildrenUpdated"];
177
        selectedPithosAccount.accountNode.childrenUpdatedNotificationName = @"SelectedPithosAccountNodeChildrenUpdated";
178
        selectedPithosAccount.sharingAccountsNode.childrenUpdatedNotificationName = @"SelectedPithosAccountNodeChildrenUpdated";
174 179
        
175 180
        [self updateAccounts];
176 181
        [self loginCancel:self];
......
221 226
    [self updateSync];
222 227
}
223 228

  
224
- (void)setSyncContainersDictionary:(NSMutableDictionary *)aSyncContainersDictionary {
225
    [syncContainersDictionary release];
226
    syncContainersDictionary = [[NSMutableDictionary alloc] initWithCapacity:[aSyncContainersDictionary count]];
227
    for (NSString *containerName in aSyncContainersDictionary) {
228
        [syncContainersDictionary setObject:[NSMutableArray arrayWithArray:[aSyncContainersDictionary objectForKey:containerName]] 
229
                                                                    forKey:containerName];
229
- (void)setSyncAccountsDictionary:(NSMutableDictionary *)aSyncAccountsDictionary {
230
    [syncAccountsDictionary release];
231
    syncAccountsDictionary = [[NSMutableDictionary alloc] initWithCapacity:[aSyncAccountsDictionary count]];
232
    for (NSString *accountName in aSyncAccountsDictionary) {
233
        NSDictionary *aSyncContainersDictionary = [aSyncAccountsDictionary objectForKey:accountName];
234
        NSMutableDictionary *syncContainersDictionary = [NSMutableDictionary dictionary];
235
        for (NSString *containerName in aSyncContainersDictionary) {
236
            [syncContainersDictionary setObject:[NSMutableArray arrayWithArray:[aSyncContainersDictionary objectForKey:containerName]] 
237
                                         forKey:containerName];
238
        }
239
        if ([syncContainersDictionary count])
240
            [syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName];
230 241
    }
231 242
    [self updateSync];
232 243
}
......
298 309
- (IBAction)syncApply:(id)sender {
299 310
    [selectedPithosAccount updateSyncWithSyncActive:syncActive 
300 311
                                  syncDirectoryPath:syncDirectoryPath 
301
                           syncContainersDictionary:syncContainersDictionary];
312
                           syncAccountsDictionary:syncAccountsDictionary];
302 313
    [self updateSync];
303 314
    pithos_macosAppDelegate *delegate = (pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate];
304 315
    [delegate savePithosAccounts:self];
......
308 319
- (IBAction)syncCancel:(id)sender {
309 320
    self.syncActive = selectedPithosAccount.syncActive;
310 321
    self.syncDirectoryPath = selectedPithosAccount.syncDirectoryPath;
311
    self.syncContainersDictionary = selectedPithosAccount.syncContainersDictionary;
312
    self.syncContainersRootFilesNodes = [NSMutableDictionary dictionary];
322
    self.syncAccountsDictionary = selectedPithosAccount.syncAccountsDictionary;
323
    self.syncAccountsRootFilesNodes = [NSMutableDictionary dictionary];
313 324
    [self selectedPithosAccountNodeChildrenUpdated:nil];
314 325
}
315 326

  
316 327
- (IBAction)syncRefresh:(id)sender {
317 328
    selectedPithosAccount.accountNode.forcedRefresh = YES;
318 329
    [selectedPithosAccount.accountNode invalidateChildrenRecursive];
319
    if (selectedPithosAccount.accountNode.children) {
330
    selectedPithosAccount.sharingAccountsNode.forcedRefresh = YES;
331
    [selectedPithosAccount.sharingAccountsNode invalidateChildrenRecursive];
332
    if (selectedPithosAccount.accountNode.children && selectedPithosAccount.sharingAccountsNode.children) {
320 333
    }
321 334
}
322 335

  
......
336 349
#pragma mark -
337 350
#pragma mark NSOutlineViewDataSource
338 351

  
352
// <my account> [PithosEmptyNode]
353
// - <container>+ [PithosContainerNode]
354
// -- <subdir>+ [PithosSubdirNode]
355
// -- <root files> [PithosEmptyNode]
356
// <sharing account>+ [PithosSharingAccountNode]
357
// - <container>+ [PithosContainerNode]
358
// -- <subdir>+ [PithosSubdirNode]
359
// -- <root files> [PithosEmptyNode]
360

  
339 361
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
340 362
    if (!selectedPithosAccount.active)
341 363
        return 0;
342
    if (outlineView == syncContainersOutlineView) {
364
    if (outlineView == syncAccountsOutlineView) {
343 365
        if (item == nil) {
366
            // root: <my account> + #<sharing account>
367
            if (selectedPithosAccount.sharingAccountsNode.children)
368
                return (selectedPithosAccount.sharingAccountsNode.children.count + 1);
369
            else
370
                return 1;
371
        } else if (item == syncAccountsMyAccountNode) {
372
            // root/<my account>: #<container>
344 373
            if (selectedPithosAccount.accountNode.children)
345 374
                return selectedPithosAccount.accountNode.children.count;
375
        } else if ([item class] == [PithosAccountNode class]) {
376
            // root/<sharing account>: #<container>
377
            PithosAccountNode *accountNode = (PithosAccountNode *)item;
378
            if (accountNode.children)
379
                return accountNode.children.count;
346 380
        } else if ([item class] == [PithosContainerNode class]) {
347
            // We add 1 for the root files node
348
            NSInteger subdirCount = 1;
349
            for (PithosNode *node in [(PithosContainerNode *)item children]) {
350
                if ([node class] == [PithosSubdirNode class])
351
                    subdirCount++;
381
            // root/{<my account>, <sharing account>}/<container>: #<subdir> + <root files>
382
            PithosContainerNode *containerNode = (PithosContainerNode *)item;
383
            if (containerNode.children) {
384
                // We add 1 for the root files node
385
                NSInteger subdirCount = 1;
386
                for (PithosNode *node in containerNode.children) {
387
                    if ([node class] == [PithosSubdirNode class])
388
                        subdirCount++;
389
                }
390
                return subdirCount;
352 391
            }
353
            return subdirCount;
354 392
        }
355 393
    }
356 394
    return 0;
357 395
}
358 396

  
359 397
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
360
    if (outlineView == syncContainersOutlineView) {
361
        if (item == nil)
398
    if (outlineView == syncAccountsOutlineView) {
399
        if (item == nil) {
400
            // root: [ <my account>, <sharing account>+ ]
401
            if (index == 0)
402
                return syncAccountsMyAccountNode;
403
            else
404
                return [selectedPithosAccount.sharingAccountsNode.children objectAtIndex:(index - 1)];
405
        } else if (item == syncAccountsMyAccountNode) {
406
            // root/<my account>: [ <container>+ ]
362 407
            return [selectedPithosAccount.accountNode.children objectAtIndex:index];
363
        if ([item class] == [PithosContainerNode class]) {
408
        } else if ([item class] == [PithosAccountNode class]) {
409
            // root/<sharing account>: [ <container>+ ]
410
            return [((PithosAccountNode *)item).children objectAtIndex:index];
411
        } else if ([item class] == [PithosContainerNode class]) {
412
            // root/{<my account>, <sharing account>}/<container>: [ <subdir>+, <root files> ]
364 413
            PithosContainerNode *containerNode = (PithosContainerNode *)item;
365 414
            NSInteger currentSubdirIndex = -1;
366 415
            for (PithosNode *node in containerNode.children) {
......
371 420
                }
372 421
            }
373 422
            if (++currentSubdirIndex == index) {
374
                PithosEmptyNode *rootFilesNode = [syncContainersRootFilesNodes objectForKey:containerNode.displayName];
423
                NSString *accountName = containerNode.sharingAccount;
424
                if (!accountName)
425
                    accountName = @"";
426
                PithosEmptyNode *rootFilesNode = [[syncAccountsRootFilesNodes objectForKey:accountName] 
427
                                                  objectForKey:containerNode.displayName];
375 428
                if (!rootFilesNode) {
429
                    if (![syncAccountsRootFilesNodes objectForKey:accountName])
430
                        [syncAccountsRootFilesNodes setObject:[NSMutableDictionary dictionary] forKey:accountName];
376 431
                    rootFilesNode = [[[PithosEmptyNode alloc] initWithDisplayName:@"<root files>" 
377 432
                                                                             icon:[[NSWorkspace sharedWorkspace] iconForFileType:@""]] 
378 433
                                     autorelease];
379 434
                    rootFilesNode.parent = containerNode;
380
                    [syncContainersRootFilesNodes setObject:rootFilesNode forKey:containerNode.displayName];
435
                    [[syncAccountsRootFilesNodes objectForKey:accountName] setObject:rootFilesNode forKey:containerNode.displayName];
381 436
                }
382 437
                return rootFilesNode;
383 438
            }
......
387 442
}
388 443

  
389 444
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
390
    if (outlineView == syncContainersOutlineView) {
391
        if ([item class] == [PithosContainerNode class])
445
    if (outlineView == syncAccountsOutlineView) {
446
        if ((item == syncAccountsMyAccountNode) || 
447
            ([item class] == [PithosAccountNode class]) || 
448
            ([item class] == [PithosContainerNode class]))
392 449
            return YES;
393 450
    }
394 451
    return NO;
395 452
}
396 453

  
397 454
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
398
    if (outlineView == syncContainersOutlineView) {
455
    if (outlineView == syncAccountsOutlineView) {
399 456
        if ([[tableColumn identifier] isEqualToString:@"sync"]) {
400
            if ([item class] == [PithosContainerNode class]) {
457
            if (item == syncAccountsMyAccountNode) {
458
                // root/<my account>
459
                // My account is 
460
                // off if not in dictionary
461
                // mixed if in dictionary with exclusions
462
                // on if in dictionary without exclusions
463
                NSMutableDictionary *syncContainersDictionary = [syncAccountsDictionary objectForKey:@""];
464
                if (syncContainersDictionary) {
465
                    for (PithosContainerNode *node in selectedPithosAccount.accountNode.children) {
466
                        NSMutableArray *containerExcludedDirectories = [syncContainersDictionary objectForKey:node.displayName];
467
                        if (!containerExcludedDirectories || [containerExcludedDirectories count])
468
                            return [NSNumber numberWithUnsignedInteger:NSMixedState];
469
                    }
470
                    return [NSNumber numberWithUnsignedInteger:NSOnState];
471
                }
472
                return [NSNumber numberWithUnsignedInteger:NSOffState];
473
            } else if ([item class] == [PithosAccountNode class]) {
474
                // root/<sharing account>
475
                // A sharing account is 
476
                // off if not in dictionary
477
                // mixed if in dictionary with exclusions
478
                // on if in dictionary without exclusions
479
                PithosAccountNode *accountNode = (PithosAccountNode *)item;
480
                NSMutableDictionary *syncContainersDictionary = [syncAccountsDictionary objectForKey:accountNode.displayName];
481
                if (syncContainersDictionary) {
482
                    for (PithosContainerNode *node in accountNode.children) {
483
                        NSMutableArray *containerExcludedDirectories = [syncContainersDictionary objectForKey:node.displayName];
484
                        if (!containerExcludedDirectories || [containerExcludedDirectories count])
485
                            return [NSNumber numberWithUnsignedInteger:NSMixedState];
486
                    }
487
                    return [NSNumber numberWithUnsignedInteger:NSOnState];
488
                }
489
                return [NSNumber numberWithUnsignedInteger:NSOffState];
490
            } else if ([item class] == [PithosContainerNode class]) {
491
                // root/{<my account>, <sharing account>}/<container>
401 492
                // A container is 
402 493
                // off if not in dictionary
403 494
                // mixed if in dictionary with exclusions
404 495
                // on if in dictionary without exclusions
405 496
                PithosContainerNode *node = (PithosContainerNode *)item;
406
                NSMutableArray *containerExcludedDirectories = [syncContainersDictionary objectForKey:node.displayName];
497
                NSString *accountName = node.sharingAccount;
498
                if (!accountName)
499
                    accountName = @"";
500
                NSMutableArray *containerExcludedDirectories = [[syncAccountsDictionary objectForKey:accountName] 
501
                                                                objectForKey:node.displayName];
407 502
                if (containerExcludedDirectories) {
408 503
                    if ([containerExcludedDirectories count])
409 504
                        return [NSNumber numberWithUnsignedInteger:NSMixedState];
......
412 507
                }
413 508
                return [NSNumber numberWithUnsignedInteger:NSOffState];
414 509
            } else if ([item class] == [PithosSubdirNode class]) {
415
                // Root files are off if parent container not in dictionary or if excluded
510
                // root/{<my account>, <sharing account>}/<container>/<subdir>
511
                // Directory is off if parent container not in dictionary or if excluded
416 512
                // displayName should be localized and lowercased
417 513
                PithosSubdirNode *node = (PithosSubdirNode *)item;
418
                NSMutableArray *containerExcludedDirectories = [syncContainersDictionary objectForKey:node.parent.displayName];
419
                NSString *directoryName = [[node.displayName lowercaseString] stringByReplacingOccurrencesOfString:@"/" withString:@":"];
420
                if (!containerExcludedDirectories || [containerExcludedDirectories containsObject:directoryName])
514
                NSString *accountName = node.sharingAccount;
515
                if (!accountName)
516
                    accountName = @"";
517
                NSMutableArray *containerExcludedDirectories = [[syncAccountsDictionary objectForKey:accountName] 
518
                                                                objectForKey:node.parent.displayName];
519
                if (!containerExcludedDirectories || 
520
                    [containerExcludedDirectories 
521
                     containsObject:[[node.displayName lowercaseString] stringByReplacingOccurrencesOfString:@"/" withString:@":"]])
421 522
                    return [NSNumber numberWithUnsignedInteger:NSOffState];
422 523
                else
423 524
                    return [NSNumber numberWithUnsignedInteger:NSOnState];
424 525
            } else if ([item class] == [PithosEmptyNode class]) {
425
                // Root files are off if parent container not in dictionary or if excluded
526
                // root/{<my account>, <sharing account>}/<container>/<root files>
527
                // Root files is off if parent container not in dictionary or if excluded
426 528
                PithosEmptyNode *node = (PithosEmptyNode *)item;
427
                NSMutableArray *containerExcludedDirectories = [syncContainersDictionary objectForKey:node.parent.displayName];
529
                NSString *accountName = node.parent.sharingAccount;
530
                if (!accountName)
531
                    accountName = @"";
532
                NSMutableArray *containerExcludedDirectories = [[syncAccountsDictionary objectForKey:accountName] 
533
                                                                objectForKey:node.parent.displayName];
428 534
                if (!containerExcludedDirectories || [containerExcludedDirectories containsObject:@""])
429 535
                    return [NSNumber numberWithUnsignedInteger:NSOffState];
430 536
                else
......
439 545
}
440 546

  
441 547
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
442
    if (outlineView == syncContainersOutlineView) {
548
    if (outlineView == syncAccountsOutlineView) {
443 549
        if ([[tableColumn identifier] isEqualToString:@"sync"]) {
444 550
            NSCellStateValue newState = [object unsignedIntegerValue];
445
            if ([item class] == [PithosContainerNode class]) {
551
            if (item == syncAccountsMyAccountNode) {
552
                // root/<my account>
553
                // If new state is
554
                // mixed/on include my account with no exclusions
555
                // off exclude my account
556
                if ((newState == NSOnState) || (newState == NSMixedState)) {
557
                    NSMutableDictionary *syncContainersDictionary = [NSMutableDictionary dictionary];
558
                    for (PithosContainerNode *node in selectedPithosAccount.accountNode.children) {
559
                        [syncContainersDictionary setObject:[NSMutableArray array] forKey:node.displayName];
560
                    }
561
                    [syncAccountsDictionary setObject:syncContainersDictionary forKey:@""];
562
                } else {
563
                    [syncAccountsDictionary removeObjectForKey:@""];
564
                }
565
                [outlineView reloadItem:item reloadChildren:YES];
566
            } else if ([item class] == [PithosAccountNode class]) {
567
                // root/<sharing account>
568
                // If new state is
569
                // mixed/on include sharing account with no exclusions
570
                // off exclude sharing account
571
                PithosAccountNode *accountNode = (PithosAccountNode *)item;
572
                if ((newState == NSOnState) || (newState == NSMixedState)) {
573
                    NSMutableDictionary *syncContainersDictionary = [NSMutableDictionary dictionary];
574
                    for (PithosContainerNode *node in accountNode.children) {
575
                        [syncContainersDictionary setObject:[NSMutableArray array] forKey:node.displayName];
576
                    }
577
                    [syncAccountsDictionary setObject:syncContainersDictionary forKey:accountNode.displayName];
578
                } else {
579
                    [syncAccountsDictionary removeObjectForKey:accountNode.displayName];
580
                }
581
                [outlineView reloadItem:item reloadChildren:YES];
582
            } else if ([item class] == [PithosContainerNode class]) {
583
                // root/{<my account>, <sharing account>}/<container>
446 584
                // If new state is
447 585
                // mixed/on include container with no excluded directories
448 586
                // off exclude container
449 587
                PithosContainerNode *node = (PithosContainerNode *)item;
588
                NSString *accountName = node.sharingAccount;
589
                PithosNode *accountNode = node.parent;
590
                if (!accountName) {
591
                    accountName = @"";
592
                    accountNode = syncAccountsMyAccountNode;
593
                }
594
                NSMutableDictionary *syncContainersDictionary = [syncAccountsDictionary objectForKey:accountName];
450 595
                if ((newState == NSOnState) || (newState == NSMixedState)) {
596
                    if (!syncContainersDictionary) {
597
                        syncContainersDictionary = [NSMutableDictionary dictionary];
598
                        [syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName];
599
                    }
451 600
                    [syncContainersDictionary setObject:[NSMutableArray array] forKey:node.displayName];
452
                } else {
601
                } else if (syncContainersDictionary) {
453 602
                    [syncContainersDictionary removeObjectForKey:node.displayName];
603
                    if (![syncContainersDictionary count])
604
                        [syncAccountsDictionary removeObjectForKey:accountName];
454 605
                }
455
                [outlineView reloadItem:item reloadChildren:YES];
606
                [outlineView reloadItem:accountNode reloadChildren:YES];
456 607
            } else if ([item class] == [PithosSubdirNode class]) {
608
                // root/{<my account>, <sharing account>}/<container>/<subdir>
457 609
                // If new state is
458 610
                // mixed/on include directory (if container not included, include and exclude all others)
459 611
                // off exclude directory
460 612
                PithosSubdirNode *node = (PithosSubdirNode *)item;
613
                NSString *accountName = node.sharingAccount;
614
                PithosNode *accountNode = node.parent.parent;
615
                if (!accountName) {
616
                    accountName = @"";
617
                    accountNode = syncAccountsMyAccountNode;
618
                }
619
                NSMutableDictionary *syncContainersDictionary = [syncAccountsDictionary objectForKey:accountName];
461 620
                NSMutableArray *containerExcludedDirectories = [syncContainersDictionary objectForKey:node.parent.displayName];
462 621
                NSString *directoryName = [[node.displayName lowercaseString] stringByReplacingOccurrencesOfString:@"/" withString:@":"];
463 622
                if ((newState == NSOnState) || (newState == NSMixedState)) {
464 623
                    if (containerExcludedDirectories) {
465 624
                        [containerExcludedDirectories removeObject:directoryName];
466 625
                    } else {
626
                        if (!syncContainersDictionary) {
627
                            syncContainersDictionary = [NSMutableDictionary dictionary];
628
                            [syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName];
629
                        }
467 630
                        NSMutableArray *newContainerExcludeDirectories = [NSMutableArray arrayWithObject:@""];
468 631
                        for (PithosNode *siblingNode in node.parent.children) {
469 632
                            if ([siblingNode class] == [PithosSubdirNode class]) {
470
                                NSString *siblingDirectoryName = [[siblingNode.displayName lowercaseString] stringByReplacingOccurrencesOfString:@"/" withString:@":"];
633
                                NSString *siblingDirectoryName = [[siblingNode.displayName lowercaseString] 
634
                                                                  stringByReplacingOccurrencesOfString:@"/" withString:@":"];
471 635
                                if (![siblingDirectoryName isEqualToString:directoryName] && 
472 636
                                    ![newContainerExcludeDirectories containsObject:siblingDirectoryName])
473 637
                                    [newContainerExcludeDirectories addObject:siblingDirectoryName];
......
475 639
                        }
476 640
                        [syncContainersDictionary setObject:newContainerExcludeDirectories forKey:node.parent.displayName];
477 641
                    }
478
                } else if (![containerExcludedDirectories containsObject:directoryName]) {
642
                } else if (syncContainersDictionary && 
643
                           containerExcludedDirectories && 
644
                           ![containerExcludedDirectories containsObject:directoryName]) {
479 645
                    [containerExcludedDirectories addObject:directoryName];
480 646
                }
481
                [outlineView reloadItem:[outlineView parentForItem:item]];
647
                [outlineView reloadItem:accountNode reloadChildren:YES];
482 648
            } else if ([item class] == [PithosEmptyNode class]) {
483 649
                // If new state is
484 650
                // mixed/on include root files (if container not included, include and exclude all others)
485 651
                // off exclude root files
486 652
                PithosEmptyNode *node = (PithosEmptyNode *)item;
653
                NSString *accountName = node.parent.sharingAccount;
654
                PithosNode *accountNode = node.parent.parent;
655
                if (!accountName) {
656
                    accountName = @"";
657
                    accountNode = syncAccountsMyAccountNode;
658
                }
659
                NSMutableDictionary *syncContainersDictionary = [syncAccountsDictionary objectForKey:accountName];
487 660
                NSMutableArray *containerExcludedDirectories = [syncContainersDictionary objectForKey:node.parent.displayName];
488 661
                if ((newState == NSOnState) || (newState == NSMixedState)) {
489 662
                    if (containerExcludedDirectories) {
490 663
                        [containerExcludedDirectories removeObject:@""];
491 664
                    } else {
665
                        if (!syncContainersDictionary) {
666
                            syncContainersDictionary = [NSMutableDictionary dictionary];
667
                            [syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName];
668
                        }
492 669
                        NSMutableArray *newContainerExcludeDirectories = [NSMutableArray array];
493 670
                        for (PithosNode *siblingNode in node.parent.children) {
494 671
                            if ([siblingNode class] == [PithosSubdirNode class]) {
495
                                NSString *siblingDirectoryName = [[siblingNode.displayName lowercaseString] stringByReplacingOccurrencesOfString:@"/" withString:@":"];
672
                                NSString *siblingDirectoryName = [[siblingNode.displayName lowercaseString] 
673
                                                                  stringByReplacingOccurrencesOfString:@"/" withString:@":"];
496 674
                                if (![newContainerExcludeDirectories containsObject:siblingDirectoryName])
497 675
                                    [newContainerExcludeDirectories addObject:siblingDirectoryName];
498 676
                            }
499 677
                        }
500 678
                        [syncContainersDictionary setObject:newContainerExcludeDirectories forKey:node.parent.displayName];
501 679
                    }
502
                } else if (![containerExcludedDirectories containsObject:@""]) {
680
                } else if (syncContainersDictionary && 
681
                           containerExcludedDirectories && 
682
                           ![containerExcludedDirectories containsObject:@""]) {
503 683
                    [containerExcludedDirectories addObject:@""];
504 684
                }
505
                [outlineView reloadItem:[outlineView parentForItem:item]];
685
                [outlineView reloadItem:accountNode reloadChildren:YES];
506 686
            }
507 687
            [self updateSync];
508 688
        }
b/pithos-macos/PithosPreferencesController.xib
82 82
											<int key="NSvFlags">256</int>
83 83
											<string key="NSFrameSize">{118, 215}</string>
84 84
											<reference key="NSSuperview" ref="475745140"/>
85
											<reference key="NSNextKeyView" ref="366650902"/>
85
											<reference key="NSWindow"/>
86
											<reference key="NSNextKeyView" ref="316124907"/>
86 87
											<string key="NSReuseIdentifierKey">_NS:1828</string>
87 88
											<bool key="NSEnabled">YES</bool>
88 89
											<object class="NSTableHeaderView" key="NSHeaderView" id="152792208">
......
90 91
												<int key="NSvFlags">256</int>
91 92
												<string key="NSFrameSize">{118, 17}</string>
92 93
												<reference key="NSSuperview" ref="316124907"/>
94
												<reference key="NSWindow"/>
93 95
												<reference key="NSNextKeyView" ref="475745140"/>
94 96
												<string key="NSReuseIdentifierKey">_NS:1830</string>
95 97
												<reference key="NSTableView" ref="260212452"/>
......
190 192
									</object>
191 193
									<string key="NSFrame">{{1, 17}, {118, 215}}</string>
192 194
									<reference key="NSSuperview" ref="419137310"/>
195
									<reference key="NSWindow"/>
193 196
									<reference key="NSNextKeyView" ref="260212452"/>
194 197
									<string key="NSReuseIdentifierKey">_NS:1826</string>
195 198
									<reference key="NSDocView" ref="260212452"/>
......
201 204
									<int key="NSvFlags">-2147483392</int>
202 205
									<string key="NSFrame">{{224, 17}, {15, 102}}</string>
203 206
									<reference key="NSSuperview" ref="419137310"/>
207
									<reference key="NSWindow"/>
204 208
									<reference key="NSNextKeyView" ref="287845150"/>
205 209
									<string key="NSReuseIdentifierKey">_NS:1845</string>
206 210
									<reference key="NSTarget" ref="419137310"/>
......
213 217
									<int key="NSvFlags">-2147483392</int>
214 218
									<string key="NSFrame">{{1, 48.325627356767654}, {82.028970718383789, 15}}</string>
215 219
									<reference key="NSSuperview" ref="419137310"/>
220
									<reference key="NSWindow"/>
216 221
									<reference key="NSNextKeyView" ref="310368570"/>
217 222
									<string key="NSReuseIdentifierKey">_NS:1847</string>
218 223
									<int key="NSsFlags">1</int>
......
229 234
									</object>
230 235
									<string key="NSFrame">{{1, 0}, {118, 17}}</string>
231 236
									<reference key="NSSuperview" ref="419137310"/>
237
									<reference key="NSWindow"/>
232 238
									<reference key="NSNextKeyView" ref="152792208"/>
233 239
									<string key="NSReuseIdentifierKey">_NS:1831</string>
234 240
									<reference key="NSDocView" ref="152792208"/>
......
238 244
							</object>
239 245
							<string key="NSFrame">{{20, 47}, {120, 233}}</string>
240 246
							<reference key="NSSuperview" ref="369507901"/>
241
							<reference key="NSNextKeyView" ref="316124907"/>
247
							<reference key="NSWindow"/>
248
							<reference key="NSNextKeyView" ref="475745140"/>
242 249
							<string key="NSReuseIdentifierKey">_NS:1824</string>
243 250
							<int key="NSsFlags">133682</int>
244 251
							<reference key="NSVScroller" ref="310368570"/>
......
252 259
							<int key="NSvFlags">18</int>
253 260
							<string key="NSFrame">{{147, 37}, {265, 249}}</string>
254 261
							<reference key="NSSuperview" ref="369507901"/>
262
							<reference key="NSWindow"/>
255 263
							<reference key="NSNextKeyView" ref="646624756"/>
256 264
							<string key="NSReuseIdentifierKey">_NS:608</string>
257 265
							<object class="NSMutableArray" key="NSTabViewItems">
......
268 276
												<int key="NSvFlags">268</int>
269 277
												<string key="NSFrame">{{14, 183}, {41, 14}}</string>
270 278
												<reference key="NSSuperview" ref="646624756"/>
279
												<reference key="NSWindow"/>
271 280
												<reference key="NSNextKeyView" ref="96425952"/>
272 281
												<bool key="NSEnabled">YES</bool>
273 282
												<object class="NSTextFieldCell" key="NSCell" id="9695847">
......
291 300
												<int key="NSvFlags">266</int>
292 301
												<string key="NSFrame">{{60, 181}, {168, 19}}</string>
293 302
												<reference key="NSSuperview" ref="646624756"/>
303
												<reference key="NSWindow"/>
294 304
												<reference key="NSNextKeyView" ref="571994001"/>
295 305
												<bool key="NSEnabled">YES</bool>
296 306
												<object class="NSTextFieldCell" key="NSCell" id="34677607">
......
319 329
												<int key="NSvFlags">266</int>
320 330
												<string key="NSFrame">{{60, 123}, {168, 19}}</string>
321 331
												<reference key="NSSuperview" ref="646624756"/>
332
												<reference key="NSWindow"/>
322 333
												<reference key="NSNextKeyView" ref="1017221490"/>
323 334
												<bool key="NSEnabled">YES</bool>
324 335
												<object class="NSTextFieldCell" key="NSCell" id="1001750419">
......
337 348
												<int key="NSvFlags">266</int>
338 349
												<string key="NSFrame">{{60, 96}, {168, 19}}</string>
339 350
												<reference key="NSSuperview" ref="646624756"/>
351
												<reference key="NSWindow"/>
340 352
												<reference key="NSNextKeyView" ref="666198740"/>
341 353
												<bool key="NSEnabled">YES</bool>
342 354
												<object class="NSTextFieldCell" key="NSCell" id="350801514">
......
355 367
												<int key="NSvFlags">268</int>
356 368
												<string key="NSFrame">{{14, 125}, {41, 14}}</string>
357 369
												<reference key="NSSuperview" ref="646624756"/>
370
												<reference key="NSWindow"/>
358 371
												<reference key="NSNextKeyView" ref="287579732"/>
359 372
												<bool key="NSEnabled">YES</bool>
360 373
												<object class="NSTextFieldCell" key="NSCell" id="993321662">
......
373 386
												<int key="NSvFlags">268</int>
374 387
												<string key="NSFrame">{{14, 98}, {41, 14}}</string>
375 388
												<reference key="NSSuperview" ref="646624756"/>
389
												<reference key="NSWindow"/>
376 390
												<reference key="NSNextKeyView" ref="773004803"/>
377 391
												<bool key="NSEnabled">YES</bool>
378 392
												<object class="NSTextFieldCell" key="NSCell" id="1037784646">
......
391 405
												<int key="NSvFlags">268</int>
392 406
												<string key="NSFrame">{{14, 150}, {86, 14}}</string>
393 407
												<reference key="NSSuperview" ref="646624756"/>
408
												<reference key="NSWindow"/>
394 409
												<reference key="NSNextKeyView" ref="507142965"/>
395 410
												<bool key="NSEnabled">YES</bool>
396 411
												<object class="NSTextFieldCell" key="NSCell" id="784421446">
......
409 424
												<int key="NSvFlags">-2147483634</int>
410 425
												<string key="NSFrame">{{-3, 170}, {251, 5}}</string>
411 426
												<reference key="NSSuperview" ref="646624756"/>
427
												<reference key="NSWindow"/>
412 428
												<reference key="NSNextKeyView" ref="992895966"/>
413 429
												<string key="NSOffsets">{0, 0}</string>
414 430
												<object class="NSTextFieldCell" key="NSTitleCell">
......
432 448
												<int key="NSvFlags">268</int>
433 449
												<string key="NSFrame">{{57, 72}, {63, 18}}</string>
434 450
												<reference key="NSSuperview" ref="646624756"/>
451
												<reference key="NSWindow"/>
435 452
												<reference key="NSNextKeyView" ref="764785507"/>
436 453
												<bool key="NSEnabled">YES</bool>
437 454
												<object class="NSButtonCell" key="NSCell" id="269907300">
......
460 477
												<int key="NSvFlags">289</int>
461 478
												<string key="NSFrame">{{161, 4}, {72, 28}}</string>
462 479
												<reference key="NSSuperview" ref="646624756"/>
463
												<reference key="NSNextKeyView"/>
480
												<reference key="NSWindow"/>
481
												<reference key="NSNextKeyView" ref="247568729"/>
464 482
												<bool key="NSEnabled">YES</bool>
465 483
												<object class="NSButtonCell" key="NSCell" id="950873176">
466 484
													<int key="NSCellFlags">-2080244224</int>
......
486 504
												<int key="NSvFlags">289</int>
487 505
												<string key="NSFrame">{{91, 4}, {72, 28}}</string>
488 506
												<reference key="NSSuperview" ref="646624756"/>
507
												<reference key="NSWindow"/>
489 508
												<reference key="NSNextKeyView" ref="750494034"/>
490 509
												<bool key="NSEnabled">YES</bool>
491 510
												<object class="NSButtonCell" key="NSCell" id="327493266">
......
506 525
										</object>
507 526
										<string key="NSFrame">{{10, 33}, {245, 203}}</string>
508 527
										<reference key="NSSuperview" ref="247568729"/>
528
										<reference key="NSWindow"/>
509 529
										<reference key="NSNextKeyView" ref="1055886655"/>
510 530
										<string key="NSReuseIdentifierKey">_NS:610</string>
511 531
									</object>
......
602 622
												<int key="NSvFlags">289</int>
603 623
												<string key="NSFrame">{{161, 4}, {72, 28}}</string>
604 624
												<reference key="NSSuperview" ref="689284120"/>
605
												<reference key="NSNextKeyView"/>
625
												<reference key="NSNextKeyView" ref="247568729"/>
606 626
												<bool key="NSEnabled">YES</bool>
607 627
												<object class="NSButtonCell" key="NSCell" id="592322209">
608 628
													<int key="NSCellFlags">-2080244224</int>
......
893 913
																<int key="NSvFlags">4352</int>
894 914
																<string key="NSFrameSize">{103, 116}</string>
895 915
																<reference key="NSSuperview" ref="748581994"/>
896
																<reference key="NSNextKeyView" ref="613407224"/>
916
																<reference key="NSNextKeyView" ref="881351662"/>
897 917
																<bool key="NSEnabled">YES</bool>
898 918
																<object class="NSTableHeaderView" key="NSHeaderView" id="94922151">
899 919
																	<reference key="NSNextResponder" ref="5455797"/>
......
1002 1022
												</object>
1003 1023
												<string key="NSFrame">{{17, 66}, {105, 134}}</string>
1004 1024
												<reference key="NSSuperview" ref="635100516"/>
1005
												<reference key="NSNextKeyView" ref="881351662"/>
1025
												<reference key="NSNextKeyView" ref="748581994"/>
1006 1026
												<int key="NSsFlags">133682</int>
1007 1027
												<reference key="NSVScroller" ref="881351662"/>
1008 1028
												<reference key="NSHScroller" ref="613407224"/>
......
1025 1045
																<int key="NSvFlags">4352</int>
1026 1046
																<string key="NSFrameSize">{103, 116}</string>
1027 1047
																<reference key="NSSuperview" ref="441382477"/>
1028
																<reference key="NSNextKeyView" ref="79495429"/>
1048
																<reference key="NSNextKeyView" ref="176697034"/>
1029 1049
																<bool key="NSEnabled">YES</bool>
1030 1050
																<object class="NSTableHeaderView" key="NSHeaderView" id="459733499">
1031 1051
																	<reference key="NSNextResponder" ref="302523439"/>
......
1134 1154
												</object>
1135 1155
												<string key="NSFrame">{{123, 66}, {105, 134}}</string>
1136 1156
												<reference key="NSSuperview" ref="635100516"/>
1137
												<reference key="NSNextKeyView" ref="176697034"/>
1157
												<reference key="NSNextKeyView" ref="441382477"/>
1138 1158
												<int key="NSsFlags">133682</int>
1139 1159
												<reference key="NSVScroller" ref="176697034"/>
1140 1160
												<reference key="NSHScroller" ref="79495429"/>
......
1241 1261
												<int key="NSvFlags">289</int>
1242 1262
												<string key="NSFrame">{{161, 4}, {72, 28}}</string>
1243 1263
												<reference key="NSSuperview" ref="635100516"/>
1244
												<reference key="NSNextKeyView"/>
1245 1264
												<bool key="NSEnabled">YES</bool>
1246 1265
												<object class="NSButtonCell" key="NSCell" id="683879656">
1247 1266
													<int key="NSCellFlags">-2080244224</int>
......
1304 1323
							<int key="NSvFlags">292</int>
1305 1324
							<string key="NSFrame">{{20, 19}, {20, 20}}</string>
1306 1325
							<reference key="NSSuperview" ref="369507901"/>
1326
							<reference key="NSWindow"/>
1307 1327
							<reference key="NSNextKeyView" ref="862152318"/>
1308 1328
							<string key="NSReuseIdentifierKey">_NS:2510</string>
1309 1329
							<bool key="NSEnabled">YES</bool>
......
1328 1348
							<int key="NSvFlags">292</int>
1329 1349
							<string key="NSFrame">{{39, 19}, {20, 20}}</string>
1330 1350
							<reference key="NSSuperview" ref="369507901"/>
1351
							<reference key="NSWindow"/>
1331 1352
							<reference key="NSNextKeyView" ref="247568729"/>
1332 1353
							<string key="NSReuseIdentifierKey">_NS:2510</string>
1333 1354
							<bool key="NSEnabled">YES</bool>
......
1350 1371
					</object>
1351 1372
					<string key="NSFrameSize">{425, 300}</string>
1352 1373
					<reference key="NSSuperview"/>
1374
					<reference key="NSWindow"/>
1353 1375
					<reference key="NSNextKeyView" ref="419137310"/>
1354 1376
				</object>
1355 1377
				<string key="NSScreenRect">{{0, 0}, {1280, 778}}</string>
......
1510 1532
					<int key="connectionID">865</int>
1511 1533
				</object>
1512 1534
				<object class="IBConnectionRecord">
1513
					<object class="IBOutletConnection" key="connection">
1514
						<string key="label">syncContainersOutlineView</string>
1515
						<reference key="source" ref="1001"/>
1516
						<reference key="destination" ref="352868425"/>
1517
					</object>
1518
					<int key="connectionID">876</int>
1519
				</object>
1520
				<object class="IBConnectionRecord">
1521 1535
					<object class="IBActionConnection" key="connection">
1522 1536
						<string key="label">syncRefresh:</string>
1523 1537
						<reference key="source" ref="1001"/>
......
1526 1540
					<int key="connectionID">886</int>
1527 1541
				</object>
1528 1542
				<object class="IBConnectionRecord">
1543
					<object class="IBOutletConnection" key="connection">
1544
						<string key="label">syncAccountsOutlineView</string>
1545
						<reference key="source" ref="1001"/>
1546
						<reference key="destination" ref="352868425"/>
1547
					</object>
1548
					<int key="connectionID">887</int>
1549
				</object>
1550
				<object class="IBConnectionRecord">
1529 1551
					<object class="IBActionConnection" key="connection">
1530 1552
						<string key="label">add:</string>
1531 1553
						<reference key="source" ref="980977849"/>
......
3307 3329
				<reference key="dict.values" ref="0"/>
3308 3330
			</object>
3309 3331
			<nil key="sourceID"/>
3310
			<int key="maxID">886</int>
3332
			<int key="maxID">887</int>
3333
		</object>
3334
		<object class="IBClassDescriber" key="IBDocument.Classes">
3335
			<object class="NSMutableArray" key="referencedPartialClassDescriptions">
3336
				<bool key="EncodedWithXMLCoder">YES</bool>
3337
				<object class="IBPartialClassDescription">
3338
					<string key="className">GroupAndGroupMemberFormatter</string>
3339
					<string key="superclassName">NSFormatter</string>
3340
					<object class="IBClassDescriptionSource" key="sourceIdentifier">
3341
						<string key="majorKey">IBProjectSource</string>
3342
						<string key="minorKey">./Classes/GroupAndGroupMemberFormatter.h</string>
3343
					</object>
3344
				</object>
3345
				<object class="IBPartialClassDescription">
3346
					<string key="className">NonEmptyStringFormatter</string>
3347
					<string key="superclassName">NSFormatter</string>
3348
					<object class="IBClassDescriptionSource" key="sourceIdentifier">
3349
						<string key="majorKey">IBProjectSource</string>
3350
						<string key="minorKey">./Classes/NonEmptyStringFormatter.h</string>
3351
					</object>
3352
				</object>
3353
				<object class="IBPartialClassDescription">
3354
					<string key="className">PithosPreferencesController</string>
3355
					<string key="superclassName">NSWindowController</string>
3356
					<object class="NSMutableDictionary" key="actions">
3357
						<bool key="EncodedWithXMLCoder">YES</bool>
3358
						<object class="NSArray" key="dict.sortedKeys">
3359
							<bool key="EncodedWithXMLCoder">YES</bool>
3360
							<string>addAccount:</string>
3361
							<string>groupsApply:</string>
3362
							<string>groupsRevert:</string>
3363
							<string>login:</string>
3364
							<string>loginCancel:</string>
3365
							<string>removeAccount:</string>
3366
							<string>syncApply:</string>
3367
							<string>syncCancel:</string>
3368
							<string>syncRefresh:</string>
3369
						</object>
3370
						<object class="NSArray" key="dict.values">
3371
							<bool key="EncodedWithXMLCoder">YES</bool>
3372
							<string>id</string>
3373
							<string>id</string>
3374
							<string>id</string>
3375
							<string>id</string>
3376
							<string>id</string>
3377
							<string>id</string>
3378
							<string>id</string>
3379
							<string>id</string>
3380
							<string>id</string>
3381
						</object>
3382
					</object>
3383
					<object class="NSMutableDictionary" key="actionInfosByName">
3384
						<bool key="EncodedWithXMLCoder">YES</bool>
3385
						<object class="NSArray" key="dict.sortedKeys">
3386
							<bool key="EncodedWithXMLCoder">YES</bool>
3387
							<string>addAccount:</string>
3388
							<string>groupsApply:</string>
3389
							<string>groupsRevert:</string>
3390
							<string>login:</string>
3391
							<string>loginCancel:</string>
3392
							<string>removeAccount:</string>
3393
							<string>syncApply:</string>
3394
							<string>syncCancel:</string>
3395
							<string>syncRefresh:</string>
3396
						</object>
3397
						<object class="NSArray" key="dict.values">
3398
							<bool key="EncodedWithXMLCoder">YES</bool>
3399
							<object class="IBActionInfo">
3400
								<string key="name">addAccount:</string>
3401
								<string key="candidateClassName">id</string>
3402
							</object>
3403
							<object class="IBActionInfo">
3404
								<string key="name">groupsApply:</string>
3405
								<string key="candidateClassName">id</string>
3406
							</object>
3407
							<object class="IBActionInfo">
3408
								<string key="name">groupsRevert:</string>
3409
								<string key="candidateClassName">id</string>
3410
							</object>
3411
							<object class="IBActionInfo">
3412
								<string key="name">login:</string>
3413
								<string key="candidateClassName">id</string>
3414
							</object>
3415
							<object class="IBActionInfo">
3416
								<string key="name">loginCancel:</string>
3417
								<string key="candidateClassName">id</string>
3418
							</object>
3419
							<object class="IBActionInfo">
3420
								<string key="name">removeAccount:</string>
3421
								<string key="candidateClassName">id</string>
3422
							</object>
3423
							<object class="IBActionInfo">
3424
								<string key="name">syncApply:</string>
3425
								<string key="candidateClassName">id</string>
3426
							</object>
3427
							<object class="IBActionInfo">
3428
								<string key="name">syncCancel:</string>
3429
								<string key="candidateClassName">id</string>
3430
							</object>
3431
							<object class="IBActionInfo">
3432
								<string key="name">syncRefresh:</string>
3433
								<string key="candidateClassName">id</string>
3434
							</object>
3435
						</object>
3436
					</object>
3437
					<object class="NSMutableDictionary" key="outlets">
3438
						<bool key="EncodedWithXMLCoder">YES</bool>
3439
						<object class="NSArray" key="dict.sortedKeys">
3440
							<bool key="EncodedWithXMLCoder">YES</bool>
3441
							<string>accountsArrayController</string>
3442
							<string>groupsDictionaryController</string>
3443
							<string>selectedGroupMembersDictionaryController</string>
3444
							<string>syncAccountsOutlineView</string>
3445
						</object>
3446
						<object class="NSArray" key="dict.values">
3447
							<bool key="EncodedWithXMLCoder">YES</bool>
3448
							<string>NSArrayController</string>
3449
							<string>NSDictionaryController</string>
3450
							<string>NSDictionaryController</string>
3451
							<string>NSOutlineView</string>
3452
						</object>
3453
					</object>
3454
					<object class="NSMutableDictionary" key="toOneOutletInfosByName">
3455
						<bool key="EncodedWithXMLCoder">YES</bool>
3456
						<object class="NSArray" key="dict.sortedKeys">
3457
							<bool key="EncodedWithXMLCoder">YES</bool>
3458
							<string>accountsArrayController</string>
3459
							<string>groupsDictionaryController</string>
3460
							<string>selectedGroupMembersDictionaryController</string>
3461
							<string>syncAccountsOutlineView</string>
3462
						</object>
3463
						<object class="NSArray" key="dict.values">
3464
							<bool key="EncodedWithXMLCoder">YES</bool>
3465
							<object class="IBToOneOutletInfo">
3466
								<string key="name">accountsArrayController</string>
3467
								<string key="candidateClassName">NSArrayController</string>
3468
							</object>
3469
							<object class="IBToOneOutletInfo">
3470
								<string key="name">groupsDictionaryController</string>
3471
								<string key="candidateClassName">NSDictionaryController</string>
3472
							</object>
3473
							<object class="IBToOneOutletInfo">
3474
								<string key="name">selectedGroupMembersDictionaryController</string>
3475
								<string key="candidateClassName">NSDictionaryController</string>
3476
							</object>
3477
							<object class="IBToOneOutletInfo">
3478
								<string key="name">syncAccountsOutlineView</string>
3479
								<string key="candidateClassName">NSOutlineView</string>
3480
							</object>
3481
						</object>
3482
					</object>
3483
					<object class="IBClassDescriptionSource" key="sourceIdentifier">
3484
						<string key="majorKey">IBProjectSource</string>
3485
						<string key="minorKey">./Classes/PithosPreferencesController.h</string>
3486
					</object>
3487
				</object>
3488
			</object>
3311 3489
		</object>
3312
		<object class="IBClassDescriber" key="IBDocument.Classes"/>
3313 3490
		<int key="IBDocument.localizationMode">0</int>
3314 3491
		<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
3315 3492
		<object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
b/pithos-macos/PithosSyncDaemon.h
44 44
@interface PithosSyncDaemon : NSObject {
45 45
    NSString *directoryPath;
46 46
    PithosAccount *pithosAccount;
47
    NSDictionary *containersDictionary;
47
    NSDictionary *accountsDictionary;
48 48
    ASIPithos *pithos;
49 49
    
50
    NSDictionary *containersDictionary;
50 51
    NSUInteger containersCount;
51 52
    NSMutableArray *pithosContainers;
52 53
    NSUInteger containersIndex;
......
76 77
}
77 78

  
78 79
@property (nonatomic, retain) NSString *directoryPath;
79
@property (nonatomic, retain) NSDictionary *containersDictionary;
80
@property (nonatomic, retain) NSDictionary *accountsDictionary;
80 81
@property (nonatomic, retain) ASIPithos *pithos;
81 82

  
83
@property (nonatomic, retain) NSDictionary *containersDictionary;
82 84
@property (nonatomic, retain) NSMutableArray *pithosContainers;
83 85

  
84 86
@property (nonatomic, retain) NSMutableDictionary *remoteObjects;
......
92 94

  
93 95
@property (nonatomic, retain) NSDate *lastCompletedSync;
94 96

  
95
// containersDictionary contains entries with keys the container names that should be included
96
// and values NSArrays that contain the directory names that should be excluded
97
// (also container root file objects with these names)
98
// An empty string denotes that all file objects in the container root should be excluded
97
// accountsDictionary contains entries of the form
98
// { <included sharing account name> : { <included container name> : [ <excluded directory names> ] } }
99
// <included sharing account name> :
100
//     the empty string "" denotes the user's own account
101
// <excluded directory names> : 
102
//     the empty string "" denotes all file objects in the container root
103
//     non-empty strings denote also container root file objects with these names
99 104
// Case insensitive filesystem is assumed, so directory names should be in lowercase
100 105
// and any trailing '/' should be replaced by ':'
101 106
- (id)initWithDirectoryPath:(NSString *)aDirectoryPath 
102 107
              pithosAccount:(PithosAccount *)aPithosAccount 
103
       containersDictionary:(NSDictionary *)aContainersDictionary 
108
         accountsDictionary:(NSDictionary *)anAccountsDictionary 
104 109
            resetLocalState:(BOOL)resetLocalState;
105 110

  
106 111
- (void)resetDaemon;
b/pithos-macos/PithosSyncDaemon.m
73 73
@end
74 74

  
75 75
@implementation PithosSyncDaemon
76
@synthesize directoryPath, containersDictionary, pithos;
77
@synthesize pithosContainers;
76
@synthesize directoryPath, accountsDictionary, pithos;
77
@synthesize containersDictionary, pithosContainers;
78 78
@synthesize lastCompletedSync, remoteObjects, previousRemoteObjects, storedLocalObjectStates, currentLocalObjectStates;
79 79
@synthesize pithosStateFilePath, tempDownloadsDirPath, tempTrashDirPath;
80 80

  
......
83 83

  
84 84
- (id)initWithDirectoryPath:(NSString *)aDirectoryPath 
85 85
              pithosAccount:(PithosAccount *)aPithosAccount 
86
       containersDictionary:(NSDictionary *)aContainersDictionary 
86
         accountsDictionary:(NSDictionary *)anAccountsDictionary 
87 87
            resetLocalState:(BOOL)resetLocalState {
88 88
    if ((self = [super init])) {
89 89
        directoryPath = [aDirectoryPath copy];
90 90
        pithosAccount = [aPithosAccount retain];
91
        containersDictionary = [aContainersDictionary copy];
91
        accountsDictionary = [anAccountsDictionary copy];
92 92
        self.pithos = pithosAccount.pithos;
93 93
        
94
        self.containersDictionary = [accountsDictionary objectForKey:@""];
95
        if (!containersDictionary)
96
            self.containersDictionary = [NSDictionary dictionary];
94 97
        containersCount = [containersDictionary count];
95 98
        self.pithosContainers = [NSMutableArray arrayWithCapacity:containersCount];
96 99
        for (NSString *containerName in containersDictionary) {
......
279 282
    [objects release];
280 283
    [lastCompletedSync release];
281 284
    [pithosContainers release];
282
    [pithos release];
283 285
    [containersDictionary release];
286
    [pithos release];
287
    [accountsDictionary release];
284 288
    [pithosAccount release];
285 289
    [directoryPath release];
286 290
    [super dealloc];
......
369 373
    }
370 374
}
371 375

  
372
- (void)setContainersDictionary:(NSDictionary *)aContainersDictionary {
373
    if (aContainersDictionary && ![aContainersDictionary isEqualToDictionary:containersDictionary]) {
376
- (void)setAccountsDictionary:(NSDictionary *)anAccountsDictionary {
377
    if (anAccountsDictionary && ![anAccountsDictionary isEqualToDictionary:accountsDictionary]) {
374 378
        [self resetDaemon];
375
        [containersDictionary release];
376
        containersDictionary = [aContainersDictionary copy];
379
        [accountsDictionary release];
380
        accountsDictionary = [anAccountsDictionary copy];
381
        
382
        self.containersDictionary = [accountsDictionary objectForKey:@""];
383
        if (!containersDictionary)
384
            self.containersDictionary = [NSDictionary dictionary];
377 385
        containersCount = [containersDictionary count];
378 386
        self.pithosContainers = [NSMutableArray arrayWithCapacity:containersCount];
379
        for (NSString *containerName in aContainersDictionary) {
387
        for (NSString *containerName in containersDictionary) {
380 388
            ASIPithosContainer *pithosContainer = [ASIPithosContainer container];
381 389
            pithosContainer.name = containerName;
382 390
            [pithosContainers addObject:pithosContainer];

Also available in: Unified diff