Created status bar icon with menu.
[pithos-macos] / pithos-macos / PithosBrowserController.m
1 //
2 //  PithosBrowserController.m
3 //  pithos-macos
4 //
5 // Copyright 2011 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 "PithosBrowserController.h"
39 #import "ASIPithosRequest.h"
40 #import "PithosAccountNode.h"
41 #import "PithosContainerNode.h"
42 #import "PithosEmptyNode.h"
43 #import "ImageAndTextCell.h"
44 #import "FileSystemBrowserCell.h"
45
46 //@interface PithosBrowserCell : NSBrowserCell {}
47 @interface PithosBrowserCell : FileSystemBrowserCell {}
48 @end
49
50 @implementation PithosBrowserCell
51
52 - (id)init {
53     if ((self = [super init])) {
54         [self setLineBreakMode:NSLineBreakByTruncatingMiddle];
55     }
56     return self;
57 }
58
59 - (void)setObjectValue:(id)object {
60     if ([object isKindOfClass:[PithosNode class]]) {
61         PithosNode *node = (PithosNode *)object;
62         [self setStringValue:node.displayName];
63         [self setImage:node.icon];
64 //        // All cells are set as leafs because a branchingImage is already set!
65 //        // Maybe this cell is already inside an NSBrowserCell
66 //        [self setLeaf:YES];
67     } else {
68         [super setObjectValue:object];
69     }
70 }
71
72 @end
73
74 @interface PithosOutlineViewCell : ImageAndTextCell {}
75 @end
76
77 @implementation PithosOutlineViewCell
78
79 - (void)setObjectValue:(id)object {
80     if ([object isKindOfClass:[PithosNode class]]) {
81         PithosNode *node = (PithosNode *)object;
82         [self setStringValue:node.displayName];
83         [self setImage:node.icon];
84         [self setEditable:NO];
85     } else {
86         [super setObjectValue:object];
87     }
88 }
89
90 @end
91
92 @interface PithosBrowserController (Private) {}
93 - (void)resetContainers;
94 @end
95
96 @implementation PithosBrowserController
97 @synthesize outlineViewDataSourceArray, splitView, outlineView, browser;
98
99 #pragma mark -
100 #pragma Object Lifecycle
101
102 - (id)init {
103     return [super initWithWindowNibName:@"PithosBrowserController"];
104 }
105
106 - (void)dealloc {
107     [[NSNotificationCenter defaultCenter] removeObserver:self];
108     [sharedPreviewController release];
109     [outlineViewDataSourceArray release];
110     [rootNode release];
111     [browser release];
112     [splitView release];
113     [outlineView release];
114     [super dealloc];
115 }
116
117 - (void)awakeFromNib {
118     [browser setCellClass:[PithosBrowserCell class]];
119 }
120
121 - (void)resetContainers {
122     rootNode = nil;
123     [browser loadColumnZero];
124     self.outlineViewDataSourceArray = nil;
125     
126     // Create the outlineView tree
127     // CONTAINERS
128         NSTreeNode *containersTreeNode = [NSTreeNode treeNodeWithRepresentedObject:
129                             [[[PithosEmptyNode alloc] initWithDisplayName:@"CONTAINERS" icon:nil] autorelease]];
130     // CONTAINERS/pithos
131         [[containersTreeNode mutableChildNodes] addObject:
132      [NSTreeNode treeNodeWithRepresentedObject:
133       [[[PithosContainerNode alloc] initWithContainerName:@"pithos" 
134                                                      icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kToolbarHomeIcon)]
135         ] autorelease]]];
136     // CONTAINERS/trash
137         [[containersTreeNode mutableChildNodes] addObject:
138      [NSTreeNode treeNodeWithRepresentedObject:
139       [[[PithosContainerNode alloc] initWithContainerName:@"trash"
140                                                      icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kFullTrashIcon)]
141         ] autorelease]]];
142     // SHARED
143         NSTreeNode *sharedTreeNode = [NSTreeNode treeNodeWithRepresentedObject:
144                                       [[[PithosEmptyNode alloc] initWithDisplayName:@"SHARED" icon:nil] autorelease]];
145     // SHARED/my shared
146         [[sharedTreeNode mutableChildNodes] addObject:
147      [NSTreeNode treeNodeWithRepresentedObject:
148       [[[PithosEmptyNode alloc] initWithDisplayName:@"my shared" 
149                                                icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kUserIcon)]
150         ] autorelease]]];
151     // SHARED/others shared
152         [[sharedTreeNode mutableChildNodes] addObject:
153      [NSTreeNode treeNodeWithRepresentedObject:
154       [[[PithosEmptyNode alloc] initWithDisplayName:@"others shared"
155                                                icon:[[NSWorkspace sharedWorkspace] iconForFileType:NSFileTypeForHFSTypeCode(kGroupIcon)]
156         ] autorelease]]];
157     
158     self.outlineViewDataSourceArray = [NSMutableArray arrayWithObjects:containersTreeNode, sharedTreeNode, nil];
159     
160         // Expand the folder outline view
161     [outlineView expandItem:nil expandChildren:YES];
162         [outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:1] byExtendingSelection:NO];
163 }
164
165 - (void)windowDidLoad {
166     [[[outlineView tableColumns] objectAtIndex:0] setDataCell:[[[PithosOutlineViewCell alloc] init] autorelease]];
167     
168     // Register for updates
169     [[NSNotificationCenter defaultCenter] addObserver:self 
170                                              selector:@selector(pithosNodeChildrenUpdated:) 
171                                                  name:@"PithosContainerNodeChildrenUpdated" 
172                                                object:nil];
173     [[NSNotificationCenter defaultCenter] addObserver:self 
174                                              selector:@selector(pithosNodeChildrenUpdated:) 
175                                                  name:@"PithosSubdirNodeChildrenUpdated" 
176                                                object:nil];
177     [[NSNotificationCenter defaultCenter] addObserver:self 
178                                              selector:@selector(resetContainers) 
179                                                  name:@"PithosAuthenticationCredentialsUpdated" 
180                                                object:nil];
181 }
182
183 #pragma mark -
184 #pragma Observers
185
186 - (void)pithosNodeChildrenUpdated:(NSNotification *)notification {
187     PithosNode *node = (PithosNode *)[notification object];
188     NSInteger lastColumn = [browser lastColumn];
189     for (NSInteger column = lastColumn; column >= 0; column--) {
190         if ([[browser parentForItemsInColumn:column] isEqualTo:node]) {
191             [browser reloadColumn:column];
192             if ((column == lastColumn - 1) && ([[browser parentForItemsInColumn:lastColumn] isLeafItem])) {
193                 // This reloads the preview column
194                 [browser setLastColumn:column];
195                 [browser addColumn];
196             }
197             return;
198         }
199     }
200 }
201
202 #pragma mark -
203 #pragma Actions
204
205 - (IBAction)refresh:(id)sender {
206     for (NSInteger column = [browser lastColumn]; column >= 0; column--) {
207         [(PithosNode *)[browser parentForItemsInColumn:column] invalidateChildren];
208     }
209     [browser validateVisibleColumns];
210 }
211
212 #pragma mark -
213 #pragma NSBrowserDelegate
214
215 - (id)rootItemForBrowser:(NSBrowser *)browser {
216     return rootNode;    
217 }
218
219 - (NSInteger)browser:(NSBrowser *)browser numberOfChildrenOfItem:(id)item {
220     PithosNode *node = (PithosNode *)item;
221     return node.children.count;
222 }
223
224 - (id)browser:(NSBrowser *)browser child:(NSInteger)index ofItem:(id)item {
225     PithosNode *node = (PithosNode *)item;
226     return [node.children objectAtIndex:index];
227 }
228
229 - (BOOL)browser:(NSBrowser *)browser isLeafItem:(id)item {
230     PithosNode *node = (PithosNode *)item;
231     return node.isLeafItem;
232 }
233
234 - (id)browser:(NSBrowser *)browser objectValueForItem:(id)item {
235     PithosNode *node = (PithosNode *)item;
236     return node;
237 }
238
239 - (NSViewController *)browser:(NSBrowser *)browser previewViewControllerForLeafItem:(id)item {
240     if (sharedPreviewController == nil)
241         sharedPreviewController = [[NSViewController alloc] initWithNibName:@"PithosBrowserPreviewController" bundle:[NSBundle bundleForClass:[self class]]];
242     return sharedPreviewController;
243 }
244
245 //- (CGFloat)browser:(NSBrowser *)browser shouldSizeColumn:(NSInteger)columnIndex forUserResize:(BOOL)forUserResize toWidth:(CGFloat)suggestedWidth  {
246 //    if (!forUserResize) {
247 //        id item = [browser parentForItemsInColumn:columnIndex]; 
248 //        if ([self browser:browser isLeafItem:item]) {
249 //            suggestedWidth = 200; 
250 //        }
251 //    }
252 //    return suggestedWidth;
253 //}
254
255 - (BOOL)browser:(NSBrowser *)sender isColumnValid:(NSInteger)column {
256     return NO;
257 }
258
259 #pragma mark -
260 #pragma NSSplitViewDelegate
261
262 - (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex {
263     return 120;
264 }
265
266 - (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex {
267     return 220;
268 }
269
270 #pragma mark -
271 #pragma mark NSOutlineViewDelegate
272
273 - (BOOL)outlineView:outlineView shouldSelectItem:(id)item {
274     return ([[item representedObject] isLeaf]);
275 }
276
277 - (BOOL)outlineView:(NSOutlineView *)outlineView isGroupItem:(id)item {
278         return (![[item representedObject] isLeaf]);
279 }
280
281 - (void)outlineViewSelectionDidChange:(NSNotification *)notification {
282     PithosNode *node = [[[outlineView itemAtRow:[outlineView selectedRow]] representedObject] representedObject];
283     if (node) {
284         rootNode = node;
285         [browser loadColumnZero];
286     }
287 }
288
289 @end