2 // PithosBrowserController.m
5 // Copyright 2011 GRNET S.A. All rights reserved.
7 // Redistribution and use in source and binary forms, with or
8 // without modification, are permitted provided that the following
11 // 1. Redistributions of source code must retain the above
12 // copyright notice, this list of conditions and the following
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.
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.
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.
38 #import "PithosBrowserController.h"
39 #import "PithosNode.h"
40 #import "PithosAccountNode.h"
41 #import "PithosContainerNode.h"
42 #import "PithosEmptyNode.h"
43 #import "ImageAndTextCell.h"
44 #import "FileSystemBrowserCell.h"
45 #import "ASIPithosRequest.h"
46 #import "ASIPithosContainerRequest.h"
47 #import "ASIPithosContainer.h"
49 //@interface PithosBrowserCell : NSBrowserCell {}
50 @interface PithosBrowserCell : FileSystemBrowserCell {}
53 @implementation PithosBrowserCell
56 if ((self = [super init])) {
57 [self setLineBreakMode:NSLineBreakByTruncatingMiddle];
62 - (void)setObjectValue:(id)object {
63 if ([object isKindOfClass:[PithosNode class]]) {
64 PithosNode *node = (PithosNode *)object;
65 [self setStringValue:node.displayName];
66 [self setImage:node.icon];
67 // // All cells are set as leafs because a branchingImage is already set!
68 // // Maybe this cell is already inside an NSBrowserCell
69 // [self setLeaf:YES];
71 [super setObjectValue:object];
77 @interface PithosOutlineViewCell : ImageAndTextCell {}
80 @implementation PithosOutlineViewCell
82 - (void)setObjectValue:(id)object {
83 if ([object isKindOfClass:[PithosNode class]]) {
84 PithosNode *node = (PithosNode *)object;
85 [self setStringValue:node.displayName];
86 [self setImage:node.icon];
87 [self setEditable:NO];
89 [super setObjectValue:object];
95 @interface PithosBrowserController (Private) {}
96 - (void)resetContainers;
99 @implementation PithosBrowserController
100 @synthesize outlineViewDataSourceArray, splitView, outlineView, browser;
103 #pragma Object Lifecycle
106 return [super initWithWindowNibName:@"PithosBrowserController"];
110 [[NSNotificationCenter defaultCenter] removeObserver:self];
111 [sharedPreviewController release];
112 [outlineViewDataSourceArray release];
113 [accountNode release];
117 [outlineView release];
121 - (void)awakeFromNib {
122 [browser setCellClass:[PithosBrowserCell class]];
125 - (void)resetContainers {
127 [browser loadColumnZero];
128 self.outlineViewDataSourceArray = nil;
130 // Create the outlineView tree
132 NSTreeNode *containersTreeNode = [NSTreeNode treeNodeWithRepresentedObject:
133 [[[PithosEmptyNode alloc] initWithDisplayName:@"CONTAINERS" icon:nil] autorelease]];
134 // // CONTAINERS/pithos
135 // [[containersTreeNode mutableChildNodes] addObject:
136 // [NSTreeNode treeNodeWithRepresentedObject:
137 // [[[PithosContainerNode alloc] initWithContainerName:@"pithos"
138 // icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kToolbarHomeIcon)]
140 // // CONTAINERS/trash
141 // [[containersTreeNode mutableChildNodes] addObject:
142 // [NSTreeNode treeNodeWithRepresentedObject:
143 // [[[PithosContainerNode alloc] initWithContainerName:@"trash"
144 // icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFullTrashIcon)]
147 NSTreeNode *sharedTreeNode = [NSTreeNode treeNodeWithRepresentedObject:
148 [[[PithosEmptyNode alloc] initWithDisplayName:@"SHARED" icon:nil] autorelease]];
150 [[sharedTreeNode mutableChildNodes] addObject:
151 [NSTreeNode treeNodeWithRepresentedObject:
152 [[[PithosEmptyNode alloc] initWithDisplayName:@"my shared"
153 icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)]
155 // SHARED/others shared
156 [[sharedTreeNode mutableChildNodes] addObject:
157 [NSTreeNode treeNodeWithRepresentedObject:
158 [[[PithosEmptyNode alloc] initWithDisplayName:@"others shared"
159 icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGroupIcon)]
162 self.outlineViewDataSourceArray = [NSMutableArray arrayWithObjects:containersTreeNode, sharedTreeNode, nil];
164 // Expand the folder outline view
165 [outlineView expandItem:nil expandChildren:YES];
166 [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
168 // Create accountNode and trigger a refresh
169 accountNode = [[PithosAccountNode alloc] init];
170 accountNode.children;
173 - (void)windowDidLoad {
174 [[[outlineView tableColumns] objectAtIndex:0] setDataCell:[[[PithosOutlineViewCell alloc] init] autorelease]];
176 // Register for updates
177 [[NSNotificationCenter defaultCenter] addObserver:self
178 selector:@selector(pithosNodeChildrenUpdated:)
179 name:@"PithosContainerNodeChildrenUpdated"
181 [[NSNotificationCenter defaultCenter] addObserver:self
182 selector:@selector(pithosNodeChildrenUpdated:)
183 name:@"PithosSubdirNodeChildrenUpdated"
185 [[NSNotificationCenter defaultCenter] addObserver:self
186 selector:@selector(pithosAccountNodeChildrenUpdated:)
187 name:@"PithosAccountNodeChildrenUpdated"
189 [[NSNotificationCenter defaultCenter] addObserver:self
190 selector:@selector(resetContainers)
191 name:@"PithosAuthenticationCredentialsUpdated"
198 - (void)pithosNodeChildrenUpdated:(NSNotification *)notification {
199 PithosNode *node = (PithosNode *)[notification object];
200 NSInteger lastColumn = [browser lastColumn];
201 for (NSInteger column = lastColumn; column >= 0; column--) {
202 if ([[browser parentForItemsInColumn:column] isEqualTo:node]) {
203 [browser reloadColumn:column];
204 if ((column == lastColumn - 1) && ([[browser parentForItemsInColumn:lastColumn] isLeafItem])) {
205 // This reloads the preview column
206 [browser setLastColumn:column];
214 - (void)pithosAccountNodeChildrenUpdated:(NSNotification *)notification {
215 BOOL containerPithosFound = NO;
216 BOOL containerTrashFound = NO;
217 //NSMutableArray *containersTreeNodeChildren = [[outlineViewDataSourceArray objectAtIndex:0] mutableChildNodes];
218 NSMutableArray *containersTreeNodeChildren = [NSMutableArray array];
219 for (PithosContainerNode *containerNode in accountNode.children) {
220 if ([containerNode.pithosContainer.name isEqualToString:@"pithos"]) {
221 containerNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kToolbarHomeIcon)];
222 [containersTreeNodeChildren insertObject:[NSTreeNode treeNodeWithRepresentedObject:containerNode] atIndex:0];
223 containerPithosFound = YES;
224 } else if ([containerNode.pithosContainer.name isEqualToString:@"trash"]) {
225 containerNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFullTrashIcon)];
226 NSUInteger insertIndex = 1;
227 if (!containerPithosFound)
229 [containersTreeNodeChildren insertObject:[NSTreeNode treeNodeWithRepresentedObject:containerNode] atIndex:insertIndex];
230 containerTrashFound = YES;
232 [containersTreeNodeChildren addObject:[NSTreeNode treeNodeWithRepresentedObject:containerNode]];
235 BOOL refreshAccountNode = NO;
236 if (!containerPithosFound) {
238 ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"pithos"];
239 [containerRequest startSynchronous];
240 if ([containerRequest error]) {
241 NSLog(@"error:%@", [containerRequest error]);
242 // XXX do something on error
244 refreshAccountNode = YES;
247 if (!containerTrashFound) {
249 ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"trash"];
250 [containerRequest startSynchronous];
251 if ([containerRequest error]) {
252 NSLog(@"error:%@", [containerRequest error]);
253 // XXX do something on error
255 refreshAccountNode = YES;
258 if (refreshAccountNode) {
259 [accountNode invalidateChildren];
260 accountNode.children;
262 [[[outlineViewDataSourceArray objectAtIndex:0] mutableChildNodes] setArray:containersTreeNodeChildren];
263 self.outlineViewDataSourceArray = outlineViewDataSourceArray;
265 // Expand the folder outline view
266 [outlineView expandItem:nil expandChildren:YES];
267 [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
275 - (IBAction)refresh:(id)sender {
276 for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
277 [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];
279 [browser validateVisibleColumns];
283 #pragma NSBrowserDelegate
285 - (id)rootItemForBrowser:(NSBrowser *)browser {
289 - (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item {
290 PithosNode *node = (PithosNode *)item;
291 return node.children.count;
294 - (id)browser:(NSBrowser *)browser child:(NSInteger)index ofItem:(id)item {
295 PithosNode *node = (PithosNode *)item;
296 return [node.children objectAtIndex:index];
299 - (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item {
300 PithosNode *node = (PithosNode *)item;
301 return node.isLeafItem;
304 - (id)browser:(NSBrowser *)browser objectValueForItem:(id)item {
305 PithosNode *node = (PithosNode *)item;
309 - (NSViewController *)browser:(NSBrowser *)browser previewViewControllerForLeafItem:(id)item {
310 if (sharedPreviewController == nil)
311 sharedPreviewController = [[NSViewController alloc] initWithNibName:@"PithosBrowserPreviewController" bundle:[NSBundle bundleForClass:[self class]]];
312 return sharedPreviewController;
315 //- (CGFloat)browser:(NSBrowser *)browser shouldSizeColumn:(NSInteger)columnIndex forUserResize:(BOOL)forUserResize toWidth:(CGFloat)suggestedWidth {
316 // if (!forUserResize) {
317 // id item = [browser parentForItemsInColumn:columnIndex];
318 // if ([self browser:browser isLeafItem:item]) {
319 // suggestedWidth = 200;
322 // return suggestedWidth;
325 - (BOOL)browser:(NSBrowser *)sender isColumnValid:(NSInteger)column {
330 #pragma NSSplitViewDelegate
332 - (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
336 - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
341 #pragma mark NSOutlineViewDelegate
343 - (BOOL)outlineView:outlineView shouldSelectItem:(id)item {
344 return ([[item representedObject] isLeaf]);
347 - (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
348 return (![[item representedObject] isLeaf]);
351 - (void)outlineViewSelectionDidChange:(NSNotification *)notification {
352 PithosNode *node = [[[outlineView itemAtRow:[outlineView selectedRow]] representedObject] representedObject];
355 [browser loadColumnZero];