root / pithos-macos / PithosPreferencesController.m @ e8dc9335
History | View | Annotate | Download (33.8 kB)
1 |
// |
---|---|
2 |
// PithosPreferencesController.m |
3 |
// pithos-macos |
4 |
// |
5 |
// Copyright 2011-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 "PithosPreferencesController.h" |
39 |
#import "PithosBrowserController.h" |
40 |
#import "PithosAccountNode.h" |
41 |
#import "PithosSharingAccountsNode.h" |
42 |
#import "PithosContainerNode.h" |
43 |
#import "PithosSubdirNode.h" |
44 |
#import "PithosObjectNode.h" |
45 |
#import "PithosEmptyNode.h" |
46 |
#import "PithosAccount.h" |
47 |
#import "pithos_macosAppDelegate.h" |
48 |
|
49 |
#import "ImageAndTextCell.h" |
50 |
@interface PithosPreferencesSyncOutlineViewCell : ImageAndTextCell {} |
51 |
@end |
52 |
|
53 |
@implementation PithosPreferencesSyncOutlineViewCell |
54 |
|
55 |
- (void)setObjectValue:(id)object { |
56 |
if ([object isKindOfClass:[PithosNode class]]) { |
57 |
PithosNode *node = (PithosNode *)object; |
58 |
[self setStringValue:node.displayName]; |
59 |
[self setImage:node.icon]; |
60 |
[self setEditable:NO]; |
61 |
} else { |
62 |
[super setObjectValue:object]; |
63 |
} |
64 |
} |
65 |
|
66 |
@end |
67 |
|
68 |
@implementation PithosPreferencesController |
69 |
@synthesize selectedPithosAccount; |
70 |
@synthesize accountsArrayController; |
71 |
@synthesize accountRemoveEnable; |
72 |
@synthesize serverURL, authUser, authToken, manual, loginEnable, loginCancelEnable; |
73 |
@synthesize syncActive, syncDirectoryPath, syncAccountsDictionary, syncApplyEnable, syncCancelEnable, |
74 |
syncAccountsOutlineView, syncAccountsRootFilesNodes; |
75 |
@synthesize groupsDictionaryController, selectedGroupMembersDictionaryController; |
76 |
|
77 |
#pragma mark - |
78 |
#pragma mark Object Lifecycle |
79 |
|
80 |
- (id)init { |
81 |
return [super initWithWindowNibName:@"PithosPreferencesController"]; |
82 |
} |
83 |
|
84 |
- (void)windowDidLoad { |
85 |
[super windowDidLoad]; |
86 |
|
87 |
NSWindow *window = [self window]; |
88 |
[window setHidesOnDeactivate:NO]; |
89 |
[window setExcludedFromWindowsMenu:YES]; |
90 |
|
91 |
// // Select the first tab when the window is loaded for the first time. |
92 |
// [[window valueForKeyPath:@"toolbar"] setSelectedItemIdentifier:@"0"]; |
93 |
|
94 |
[[[syncAccountsOutlineView tableColumns] objectAtIndex:1] setDataCell:[[[PithosPreferencesSyncOutlineViewCell alloc] init] autorelease]]; |
95 |
syncAccountsMyAccountNode = [[PithosEmptyNode alloc] initWithDisplayName:@"<my account>" |
96 |
icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)]]; |
97 |
|
98 |
[groupsDictionaryController setInitialKey:@"group"]; |
99 |
[groupsDictionaryController setInitialValue:@"user"]; |
100 |
[selectedGroupMembersDictionaryController setInitialKey:@"user"]; |
101 |
[selectedGroupMembersDictionaryController setInitialValue:@""]; |
102 |
|
103 |
[window setDelegate:self]; |
104 |
|
105 |
self.selectedPithosAccount = [[accountsArrayController selectedObjects] objectAtIndex:0]; |
106 |
[accountsArrayController addObserver:self forKeyPath:@"selection" options:NSKeyValueObservingOptionNew context:NULL]; |
107 |
[[NSNotificationCenter defaultCenter] addObserver:self |
108 |
selector:@selector(selectedPithosAccountNodeChildrenUpdated:) |
109 |
name:@"SelectedPithosAccountNodeChildrenUpdated" |
110 |
object:nil]; |
111 |
} |
112 |
|
113 |
- (BOOL)windowShouldClose:(id)sender { |
114 |
return [(pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate] activated]; |
115 |
} |
116 |
|
117 |
//- (void)windowWillClose:(NSNotification *)notification { |
118 |
//} |
119 |
|
120 |
//- (IBAction)toolbarItemSelected:(id)sender { |
121 |
//} |
122 |
|
123 |
#pragma mark - |
124 |
#pragma Observers |
125 |
|
126 |
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { |
127 |
if ([object isEqualTo:accountsArrayController] && |
128 |
[keyPath isEqualToString:@"selection"] && |
129 |
[[accountsArrayController selectedObjects] count]) { |
130 |
self.selectedPithosAccount = [[accountsArrayController selectedObjects] objectAtIndex:0]; |
131 |
} |
132 |
} |
133 |
|
134 |
- (void)selectedPithosAccountNodeChildrenUpdated:(NSNotification *)notification { |
135 |
[syncAccountsOutlineView reloadData]; |
136 |
[syncAccountsOutlineView expandItem:nil expandChildren:YES]; |
137 |
} |
138 |
|
139 |
#pragma mark - |
140 |
#pragma Update |
141 |
|
142 |
- (void)updateAccounts { |
143 |
pithos_macosAppDelegate *delegate = (pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate]; |
144 |
self.accountRemoveEnable = (delegate.activated && ([delegate.pithosAccounts count] > 1)); |
145 |
} |
146 |
|
147 |
- (void)updateLogin { |
148 |
self.loginEnable = ([selectedPithosAccount urlIsValid:serverURL] && (!manual || ([authUser length] && [authToken length]))); |
149 |
self.loginCancelEnable = (![selectedPithosAccount.serverURL isEqualToString:serverURL] || |
150 |
(selectedPithosAccount.authUser && ![selectedPithosAccount.authUser isEqualToString:authUser]) || |
151 |
(selectedPithosAccount.authToken && ![selectedPithosAccount.authToken isEqualToString:authToken])); |
152 |
} |
153 |
|
154 |
- (void)updateSync { |
155 |
BOOL isDirectory; |
156 |
self.syncApplyEnable = (selectedPithosAccount.active && |
157 |
((selectedPithosAccount.syncActive != syncActive) || |
158 |
(![selectedPithosAccount.syncDirectoryPath isEqualToString:syncDirectoryPath] && |
159 |
(![[NSFileManager defaultManager] fileExistsAtPath:syncDirectoryPath isDirectory:&isDirectory] || |
160 |
isDirectory)) || |
161 |
![selectedPithosAccount.syncAccountsDictionary isEqualToDictionary:syncAccountsDictionary])); |
162 |
self.syncCancelEnable = (selectedPithosAccount.active && |
163 |
((selectedPithosAccount.syncActive != syncActive) || |
164 |
![selectedPithosAccount.syncDirectoryPath isEqualToString:syncDirectoryPath] || |
165 |
![selectedPithosAccount.syncAccountsDictionary isEqualToDictionary:syncAccountsDictionary])); |
166 |
} |
167 |
|
168 |
#pragma mark - |
169 |
#pragma Properties |
170 |
|
171 |
- (void)setSelectedPithosAccount:(PithosAccount *)aSelectedPithosAccount { |
172 |
if (aSelectedPithosAccount && ![aSelectedPithosAccount isEqualTo:selectedPithosAccount]) { |
173 |
selectedPithosAccount.accountNode.childrenUpdatedNotificationName = nil; |
174 |
selectedPithosAccount.sharingAccountsNode.childrenUpdatedNotificationName = nil; |
175 |
[selectedPithosAccount release]; |
176 |
selectedPithosAccount = [aSelectedPithosAccount retain]; |
177 |
selectedPithosAccount.accountNode.childrenUpdatedNotificationName = @"SelectedPithosAccountNodeChildrenUpdated"; |
178 |
selectedPithosAccount.sharingAccountsNode.childrenUpdatedNotificationName = @"SelectedPithosAccountNodeChildrenUpdated"; |
179 |
|
180 |
[self updateAccounts]; |
181 |
[self loginCancel:self]; |
182 |
[self syncCancel:self]; |
183 |
[self groupsRevert:self]; |
184 |
} |
185 |
} |
186 |
|
187 |
#pragma Login Properties |
188 |
|
189 |
- (void)setServerURL:(NSString *)aServerURL { |
190 |
[serverURL release]; |
191 |
serverURL = [aServerURL copy]; |
192 |
[self updateLogin]; |
193 |
} |
194 |
|
195 |
- (void)setAuthUser:(NSString *)anAuthUser { |
196 |
[authUser release]; |
197 |
authUser = [anAuthUser copy]; |
198 |
[self updateLogin]; |
199 |
} |
200 |
|
201 |
- (void)setAuthToken:(NSString *)anAuthToken { |
202 |
[authToken release]; |
203 |
authToken = [anAuthToken copy]; |
204 |
[self updateLogin]; |
205 |
} |
206 |
|
207 |
- (void)setManual:(BOOL)aManual { |
208 |
manual = aManual; |
209 |
[self updateLogin]; |
210 |
if (!manual) { |
211 |
self.authUser = selectedPithosAccount.authUser; |
212 |
self.authToken = selectedPithosAccount.authToken; |
213 |
} |
214 |
} |
215 |
|
216 |
#pragma Sync Properties |
217 |
|
218 |
- (void)setSyncActive:(BOOL)aSyncActive { |
219 |
syncActive = aSyncActive; |
220 |
[self updateSync]; |
221 |
} |
222 |
|
223 |
- (void)setSyncDirectoryPath:(NSString *)aSyncDirectoryPath { |
224 |
[syncDirectoryPath release]; |
225 |
syncDirectoryPath = [aSyncDirectoryPath copy]; |
226 |
[self updateSync]; |
227 |
} |
228 |
|
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]; |
241 |
} |
242 |
[self updateSync]; |
243 |
} |
244 |
|
245 |
#pragma mark - |
246 |
#pragma Actions |
247 |
|
248 |
- (IBAction)addAccount:(id)sender { |
249 |
[accountsArrayController addObject:[PithosAccount pithosAccount]]; |
250 |
[self updateAccounts]; |
251 |
pithos_macosAppDelegate *delegate = (pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate]; |
252 |
[delegate.pithosAccountsDictionary setObject:selectedPithosAccount forKey:selectedPithosAccount.name]; |
253 |
[delegate savePithosAccounts:self]; |
254 |
} |
255 |
|
256 |
- (IBAction)removeAccount:(id)sender { |
257 |
[self updateAccounts]; |
258 |
if (!accountRemoveEnable) |
259 |
return; |
260 |
PithosAccount *removedPithosAccount = [selectedPithosAccount retain]; |
261 |
pithos_macosAppDelegate *delegate = (pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate]; |
262 |
if ([delegate.currentPithosAccount isEqualTo:removedPithosAccount] && [delegate.pithosBrowserController operationsPending]) { |
263 |
NSAlert *alert = [[[NSAlert alloc] init] autorelease]; |
264 |
[alert setMessageText:@"Operations Pending"]; |
265 |
[alert setInformativeText:@"There are pending operations in the browser, do you want to remove the account and cancel them?"]; |
266 |
[alert addButtonWithTitle:@"OK"]; |
267 |
[alert addButtonWithTitle:@"Cancel"]; |
268 |
NSInteger choice = [alert runModal]; |
269 |
if (choice == NSAlertSecondButtonReturn) { |
270 |
[removedPithosAccount release]; |
271 |
return; |
272 |
} |
273 |
} |
274 |
[accountsArrayController removeObject:selectedPithosAccount]; |
275 |
[delegate.pithosAccountsDictionary removeObjectForKey:removedPithosAccount.name]; |
276 |
[delegate removedPithosAccount:removedPithosAccount]; |
277 |
[delegate savePithosAccounts:self]; |
278 |
[removedPithosAccount release]; |
279 |
[self updateAccounts]; |
280 |
} |
281 |
|
282 |
#pragma Login Actions |
283 |
|
284 |
- (IBAction)login:(id)sender { |
285 |
if (!manual) { |
286 |
[selectedPithosAccount loginWithServerURL:serverURL]; |
287 |
} else { |
288 |
[selectedPithosAccount authenticateWithServerURL:serverURL authUser:authUser authToken:authToken]; |
289 |
self.manual = NO; |
290 |
pithos_macosAppDelegate *delegate = (pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate]; |
291 |
[delegate savePithosAccounts:self]; |
292 |
if (!delegate.activated) { |
293 |
delegate.activated = YES; |
294 |
[delegate showPithosBrowser:self]; |
295 |
} |
296 |
if ([selectedPithosAccount isEqualTo:delegate.currentPithosAccount]) |
297 |
delegate.pithosBrowserController.pithos = selectedPithosAccount.pithos; |
298 |
} |
299 |
} |
300 |
|
301 |
- (IBAction)loginCancel:(id)server { |
302 |
self.serverURL = selectedPithosAccount.serverURL; |
303 |
self.authUser = selectedPithosAccount.authUser; |
304 |
self.authToken = selectedPithosAccount.authToken; |
305 |
} |
306 |
|
307 |
#pragma Sync Actions |
308 |
|
309 |
- (IBAction)syncApply:(id)sender { |
310 |
[selectedPithosAccount updateSyncWithSyncActive:syncActive |
311 |
syncDirectoryPath:syncDirectoryPath |
312 |
syncAccountsDictionary:syncAccountsDictionary]; |
313 |
[self updateSync]; |
314 |
pithos_macosAppDelegate *delegate = (pithos_macosAppDelegate *)[[NSApplication sharedApplication] delegate]; |
315 |
[delegate savePithosAccounts:self]; |
316 |
[delegate sync]; |
317 |
} |
318 |
|
319 |
- (IBAction)syncCancel:(id)sender { |
320 |
self.syncActive = selectedPithosAccount.syncActive; |
321 |
self.syncDirectoryPath = selectedPithosAccount.syncDirectoryPath; |
322 |
self.syncAccountsDictionary = selectedPithosAccount.syncAccountsDictionary; |
323 |
self.syncAccountsRootFilesNodes = [NSMutableDictionary dictionary]; |
324 |
[self selectedPithosAccountNodeChildrenUpdated:nil]; |
325 |
} |
326 |
|
327 |
- (IBAction)syncRefresh:(id)sender { |
328 |
selectedPithosAccount.accountNode.forcedRefresh = YES; |
329 |
[selectedPithosAccount.accountNode invalidateChildrenRecursive]; |
330 |
selectedPithosAccount.sharingAccountsNode.forcedRefresh = YES; |
331 |
[selectedPithosAccount.sharingAccountsNode invalidateChildrenRecursive]; |
332 |
if (selectedPithosAccount.accountNode.children && selectedPithosAccount.sharingAccountsNode.children) { |
333 |
} |
334 |
} |
335 |
|
336 |
#pragma mark Groups Actions |
337 |
|
338 |
- (IBAction)groupsApply:(id)sender { |
339 |
[[self window] makeFirstResponder:nil]; |
340 |
if (selectedPithosAccount.active) |
341 |
[selectedPithosAccount.accountNode applyInfo]; |
342 |
} |
343 |
|
344 |
- (IBAction)groupsRevert:(id)sender { |
345 |
if (selectedPithosAccount.active && selectedPithosAccount.accountNode) |
346 |
[selectedPithosAccount.accountNode refreshInfo]; |
347 |
} |
348 |
|
349 |
#pragma mark - |
350 |
#pragma mark NSOutlineViewDataSource |
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 |
|
361 |
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item { |
362 |
if (!selectedPithosAccount.active) |
363 |
return 0; |
364 |
if (outlineView == syncAccountsOutlineView) { |
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> |
373 |
if (selectedPithosAccount.accountNode.children) |
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; |
380 |
} else if ([item class] == [PithosContainerNode class]) { |
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; |
391 |
} |
392 |
} |
393 |
} |
394 |
return 0; |
395 |
} |
396 |
|
397 |
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item { |
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>+ ] |
407 |
return [selectedPithosAccount.accountNode.children objectAtIndex:index]; |
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> ] |
413 |
PithosContainerNode *containerNode = (PithosContainerNode *)item; |
414 |
NSInteger currentSubdirIndex = -1; |
415 |
for (PithosNode *node in containerNode.children) { |
416 |
if ([node class] == [PithosSubdirNode class]) { |
417 |
currentSubdirIndex++; |
418 |
if (currentSubdirIndex == index) |
419 |
return node; |
420 |
} |
421 |
} |
422 |
if (++currentSubdirIndex == index) { |
423 |
NSString *accountName = containerNode.sharingAccount; |
424 |
if (!accountName) |
425 |
accountName = @""; |
426 |
PithosEmptyNode *rootFilesNode = [[syncAccountsRootFilesNodes objectForKey:accountName] |
427 |
objectForKey:containerNode.displayName]; |
428 |
if (!rootFilesNode) { |
429 |
if (![syncAccountsRootFilesNodes objectForKey:accountName]) |
430 |
[syncAccountsRootFilesNodes setObject:[NSMutableDictionary dictionary] forKey:accountName]; |
431 |
rootFilesNode = [[[PithosEmptyNode alloc] initWithDisplayName:@"<root files>" |
432 |
icon:[[NSWorkspace sharedWorkspace] iconForFileType:@""]] |
433 |
autorelease]; |
434 |
rootFilesNode.parent = containerNode; |
435 |
[[syncAccountsRootFilesNodes objectForKey:accountName] setObject:rootFilesNode forKey:containerNode.displayName]; |
436 |
} |
437 |
return rootFilesNode; |
438 |
} |
439 |
} |
440 |
} |
441 |
return nil; |
442 |
} |
443 |
|
444 |
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item { |
445 |
if (outlineView == syncAccountsOutlineView) { |
446 |
if ((item == syncAccountsMyAccountNode) || |
447 |
([item class] == [PithosAccountNode class]) || |
448 |
([item class] == [PithosContainerNode class])) |
449 |
return YES; |
450 |
} |
451 |
return NO; |
452 |
} |
453 |
|
454 |
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { |
455 |
if (outlineView == syncAccountsOutlineView) { |
456 |
if ([[tableColumn identifier] isEqualToString:@"sync"]) { |
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> |
492 |
// A container is |
493 |
// off if not in dictionary |
494 |
// mixed if in dictionary with exclusions |
495 |
// on if in dictionary without exclusions |
496 |
PithosContainerNode *node = (PithosContainerNode *)item; |
497 |
NSString *accountName = node.sharingAccount; |
498 |
if (!accountName) |
499 |
accountName = @""; |
500 |
NSMutableArray *containerExcludedDirectories = [[syncAccountsDictionary objectForKey:accountName] |
501 |
objectForKey:node.displayName]; |
502 |
if (containerExcludedDirectories) { |
503 |
if ([containerExcludedDirectories count]) |
504 |
return [NSNumber numberWithUnsignedInteger:NSMixedState]; |
505 |
else |
506 |
return [NSNumber numberWithUnsignedInteger:NSOnState]; |
507 |
} |
508 |
return [NSNumber numberWithUnsignedInteger:NSOffState]; |
509 |
} else if ([item class] == [PithosSubdirNode class]) { |
510 |
// root/{<my account>, <sharing account>}/<container>/<subdir> |
511 |
// Directory is off if parent container not in dictionary or if excluded |
512 |
// displayName should be localized and lowercased |
513 |
PithosSubdirNode *node = (PithosSubdirNode *)item; |
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:@":"]]) |
522 |
return [NSNumber numberWithUnsignedInteger:NSOffState]; |
523 |
else |
524 |
return [NSNumber numberWithUnsignedInteger:NSOnState]; |
525 |
} else if ([item class] == [PithosEmptyNode class]) { |
526 |
// root/{<my account>, <sharing account>}/<container>/<root files> |
527 |
// Root files is off if parent container not in dictionary or if excluded |
528 |
PithosEmptyNode *node = (PithosEmptyNode *)item; |
529 |
NSString *accountName = node.parent.sharingAccount; |
530 |
if (!accountName) |
531 |
accountName = @""; |
532 |
NSMutableArray *containerExcludedDirectories = [[syncAccountsDictionary objectForKey:accountName] |
533 |
objectForKey:node.parent.displayName]; |
534 |
if (!containerExcludedDirectories || [containerExcludedDirectories containsObject:@""]) |
535 |
return [NSNumber numberWithUnsignedInteger:NSOffState]; |
536 |
else |
537 |
return [NSNumber numberWithUnsignedInteger:NSOnState]; |
538 |
} |
539 |
return [NSNumber numberWithUnsignedInteger:NSOffState]; |
540 |
} else if ([[tableColumn identifier] isEqualToString:@"path"]) { |
541 |
return (PithosNode *)item; |
542 |
} |
543 |
} |
544 |
return nil; |
545 |
} |
546 |
|
547 |
- (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { |
548 |
if (outlineView == syncAccountsOutlineView) { |
549 |
if ([[tableColumn identifier] isEqualToString:@"sync"]) { |
550 |
NSCellStateValue newState = [object unsignedIntegerValue]; |
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> |
584 |
// If new state is |
585 |
// mixed/on include container with no excluded directories |
586 |
// off exclude container |
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]; |
595 |
if ((newState == NSOnState) || (newState == NSMixedState)) { |
596 |
if (!syncContainersDictionary) { |
597 |
syncContainersDictionary = [NSMutableDictionary dictionary]; |
598 |
[syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName]; |
599 |
} |
600 |
[syncContainersDictionary setObject:[NSMutableArray array] forKey:node.displayName]; |
601 |
} else if (syncContainersDictionary) { |
602 |
[syncContainersDictionary removeObjectForKey:node.displayName]; |
603 |
if (![syncContainersDictionary count]) |
604 |
[syncAccountsDictionary removeObjectForKey:accountName]; |
605 |
} |
606 |
[outlineView reloadItem:accountNode reloadChildren:YES]; |
607 |
} else if ([item class] == [PithosSubdirNode class]) { |
608 |
// root/{<my account>, <sharing account>}/<container>/<subdir> |
609 |
// If new state is |
610 |
// mixed/on include directory (if container not included, include and exclude all others) |
611 |
// off exclude directory |
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]; |
620 |
NSMutableArray *containerExcludedDirectories = [syncContainersDictionary objectForKey:node.parent.displayName]; |
621 |
NSString *directoryName = [[node.displayName lowercaseString] stringByReplacingOccurrencesOfString:@"/" withString:@":"]; |
622 |
if ((newState == NSOnState) || (newState == NSMixedState)) { |
623 |
if (containerExcludedDirectories) { |
624 |
[containerExcludedDirectories removeObject:directoryName]; |
625 |
} else { |
626 |
if (!syncContainersDictionary) { |
627 |
syncContainersDictionary = [NSMutableDictionary dictionary]; |
628 |
[syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName]; |
629 |
} |
630 |
NSMutableArray *newContainerExcludeDirectories = [NSMutableArray arrayWithObject:@""]; |
631 |
for (PithosNode *siblingNode in node.parent.children) { |
632 |
if ([siblingNode class] == [PithosSubdirNode class]) { |
633 |
NSString *siblingDirectoryName = [[siblingNode.displayName lowercaseString] |
634 |
stringByReplacingOccurrencesOfString:@"/" withString:@":"]; |
635 |
if (![siblingDirectoryName isEqualToString:directoryName] && |
636 |
![newContainerExcludeDirectories containsObject:siblingDirectoryName]) |
637 |
[newContainerExcludeDirectories addObject:siblingDirectoryName]; |
638 |
} |
639 |
} |
640 |
[syncContainersDictionary setObject:newContainerExcludeDirectories forKey:node.parent.displayName]; |
641 |
} |
642 |
} else if (syncContainersDictionary && |
643 |
containerExcludedDirectories && |
644 |
![containerExcludedDirectories containsObject:directoryName]) { |
645 |
[containerExcludedDirectories addObject:directoryName]; |
646 |
} |
647 |
[outlineView reloadItem:accountNode reloadChildren:YES]; |
648 |
} else if ([item class] == [PithosEmptyNode class]) { |
649 |
// If new state is |
650 |
// mixed/on include root files (if container not included, include and exclude all others) |
651 |
// off exclude root files |
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]; |
660 |
NSMutableArray *containerExcludedDirectories = [syncContainersDictionary objectForKey:node.parent.displayName]; |
661 |
if ((newState == NSOnState) || (newState == NSMixedState)) { |
662 |
if (containerExcludedDirectories) { |
663 |
[containerExcludedDirectories removeObject:@""]; |
664 |
} else { |
665 |
if (!syncContainersDictionary) { |
666 |
syncContainersDictionary = [NSMutableDictionary dictionary]; |
667 |
[syncAccountsDictionary setObject:syncContainersDictionary forKey:accountName]; |
668 |
} |
669 |
NSMutableArray *newContainerExcludeDirectories = [NSMutableArray array]; |
670 |
for (PithosNode *siblingNode in node.parent.children) { |
671 |
if ([siblingNode class] == [PithosSubdirNode class]) { |
672 |
NSString *siblingDirectoryName = [[siblingNode.displayName lowercaseString] |
673 |
stringByReplacingOccurrencesOfString:@"/" withString:@":"]; |
674 |
if (![newContainerExcludeDirectories containsObject:siblingDirectoryName]) |
675 |
[newContainerExcludeDirectories addObject:siblingDirectoryName]; |
676 |
} |
677 |
} |
678 |
[syncContainersDictionary setObject:newContainerExcludeDirectories forKey:node.parent.displayName]; |
679 |
} |
680 |
} else if (syncContainersDictionary && |
681 |
containerExcludedDirectories && |
682 |
![containerExcludedDirectories containsObject:@""]) { |
683 |
[containerExcludedDirectories addObject:@""]; |
684 |
} |
685 |
[outlineView reloadItem:accountNode reloadChildren:YES]; |
686 |
} |
687 |
[self updateSync]; |
688 |
} |
689 |
} |
690 |
} |
691 |
|
692 |
@end |