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 [super windowDidLoad];
176 [[[outlineView tableColumns] objectAtIndex:0] setDataCell:[[[PithosOutlineViewCell alloc] init] autorelease]];
178 // Register for updates
179 [[NSNotificationCenter defaultCenter] addObserver:self
180 selector:@selector(pithosNodeChildrenUpdated:)
181 name:@"PithosContainerNodeChildrenUpdated"
183 [[NSNotificationCenter defaultCenter] addObserver:self
184 selector:@selector(pithosNodeChildrenUpdated:)
185 name:@"PithosSubdirNodeChildrenUpdated"
187 [[NSNotificationCenter defaultCenter] addObserver:self
188 selector:@selector(pithosAccountNodeChildrenUpdated:)
189 name:@"PithosAccountNodeChildrenUpdated"
191 [[NSNotificationCenter defaultCenter] addObserver:self
192 selector:@selector(resetContainers)
193 name:@"PithosAuthenticationCredentialsUpdated"
200 - (void)pithosNodeChildrenUpdated:(NSNotification *)notification {
201 PithosNode *node = (PithosNode *)[notification object];
202 NSInteger lastColumn = [browser lastColumn];
203 for (NSInteger column = lastColumn; column >= 0; column--) {
204 if ([[browser parentForItemsInColumn:column] isEqualTo:node]) {
205 [browser reloadColumn:column];
206 if ((column == lastColumn - 1) && ([[browser parentForItemsInColumn:lastColumn] isLeafItem])) {
207 // This reloads the preview column
208 [browser setLastColumn:column];
216 - (void)pithosAccountNodeChildrenUpdated:(NSNotification *)notification {
217 BOOL containerPithosFound = NO;
218 BOOL containerTrashFound = NO;
219 //NSMutableArray *containersTreeNodeChildren = [[outlineViewDataSourceArray objectAtIndex:0] mutableChildNodes];
220 NSMutableArray *containersTreeNodeChildren = [NSMutableArray array];
221 for (PithosContainerNode *containerNode in accountNode.children) {
222 if ([containerNode.pithosContainer.name isEqualToString:@"pithos"]) {
223 containerNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kToolbarHomeIcon)];
224 [containersTreeNodeChildren insertObject:[NSTreeNode treeNodeWithRepresentedObject:containerNode] atIndex:0];
225 containerPithosFound = YES;
226 } else if ([containerNode.pithosContainer.name isEqualToString:@"trash"]) {
227 containerNode.icon = [[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFullTrashIcon)];
228 NSUInteger insertIndex = 1;
229 if (!containerPithosFound)
231 [containersTreeNodeChildren insertObject:[NSTreeNode treeNodeWithRepresentedObject:containerNode] atIndex:insertIndex];
232 containerTrashFound = YES;
234 [containersTreeNodeChildren addObject:[NSTreeNode treeNodeWithRepresentedObject:containerNode]];
237 BOOL refreshAccountNode = NO;
238 if (!containerPithosFound) {
240 ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"pithos"];
241 [containerRequest startSynchronous];
242 if ([containerRequest error]) {
243 NSLog(@"error:%@", [containerRequest error]);
244 // XXX do something on error
246 refreshAccountNode = YES;
249 if (!containerTrashFound) {
251 ASIPithosContainerRequest *containerRequest = [ASIPithosContainerRequest createOrUpdateContainerRequestWithContainerName:@"trash"];
252 [containerRequest startSynchronous];
253 if ([containerRequest error]) {
254 NSLog(@"error:%@", [containerRequest error]);
255 // XXX do something on error
257 refreshAccountNode = YES;
260 if (refreshAccountNode) {
261 [accountNode invalidateChildren];
262 accountNode.children;
264 [[[outlineViewDataSourceArray objectAtIndex:0] mutableChildNodes] setArray:containersTreeNodeChildren];
265 self.outlineViewDataSourceArray = outlineViewDataSourceArray;
267 // Expand the folder outline view
268 [outlineView expandItem:nil expandChildren:YES];
269 [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
277 - (IBAction)refresh:(id)sender {
278 for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
279 [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];
281 [browser validateVisibleColumns];
285 #pragma NSBrowserDelegate
287 - (id)rootItemForBrowser:(NSBrowser *)browser {
291 - (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item {
292 PithosNode *node = (PithosNode *)item;
293 return node.children.count;
296 - (id)browser:(NSBrowser *)browser child:(NSInteger)index ofItem:(id)item {
297 PithosNode *node = (PithosNode *)item;
298 return [node.children objectAtIndex:index];
301 - (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item {
302 PithosNode *node = (PithosNode *)item;
303 return node.isLeafItem;
306 - (id)browser:(NSBrowser *)browser objectValueForItem:(id)item {
307 PithosNode *node = (PithosNode *)item;
311 - (NSViewController *)browser:(NSBrowser *)browser previewViewControllerForLeafItem:(id)item {
312 if (sharedPreviewController == nil)
313 sharedPreviewController = [[NSViewController alloc] initWithNibName:@"PithosBrowserPreviewController" bundle:[NSBundle bundleForClass:[self class]]];
314 return sharedPreviewController;
317 //- (CGFloat)browser:(NSBrowser *)browser shouldSizeColumn:(NSInteger)columnIndex forUserResize:(BOOL)forUserResize toWidth:(CGFloat)suggestedWidth {
318 // if (!forUserResize) {
319 // id item = [browser parentForItemsInColumn:columnIndex];
320 // if ([self browser:browser isLeafItem:item]) {
321 // suggestedWidth = 200;
324 // return suggestedWidth;
327 - (BOOL)browser:(NSBrowser *)sender isColumnValid:(NSInteger)column {
332 #pragma NSSplitViewDelegate
334 - (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
338 - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
343 #pragma mark NSOutlineViewDelegate
345 - (BOOL)outlineView:outlineView shouldSelectItem:(id)item {
346 return ([[item representedObject] isLeaf]);
349 - (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
350 return (![[item representedObject] isLeaf]);
353 - (void)outlineViewSelectionDidChange:(NSNotification *)notification {
354 PithosNode *node = [[[outlineView itemAtRow:[outlineView selectedRow]] representedObject] representedObject];
357 [browser loadColumnZero];