OSDN Git Service

0.2.1
[eliscolors/main.git] / ElisMediaBrowserController.m
1 //  Copyright (c) 2009 Yanagi Asakura
2 //
3 //  This software is provided 'as-is', without any express or implied
4 //  warranty. In no event will the authors be held liable for any damages
5 //  arising from the use of this software.
6 //
7 //  Permission is granted to anyone to use this software for any purpose,
8 //  including commercial applications, and to alter it and redistribute it
9 //  freely, subject to the following restrictions:
10 //
11 //  1. The origin of this software must not be misrepresented; you must not
12 //  claim that you wrote the original software. If you use this software
13 //  in a product, an acknowledgment in the product documentation would be
14 //  appreciated but is not required.
15 //
16 //  2. Altered source versions must be plainly marked as such, and must not be
17 //  misrepresented as being the original software.
18 //
19 //  3. This notice may not be removed or altered from any source
20 //  distribution.
21
22 //
23 //  ElisMediaBrowserController.m
24 //  Elis Colors
25 //
26 //  Created by 柳 on 09/09/17.
27 //  Copyright 2009 __MyCompanyName__. All rights reserved.
28 //
29
30 #import "ElisMediaBrowserController.h"
31
32 /* openFiles is a simple C function that open an NSOpenPanel and return an array of selected filepath */
33 static NSArray *openFiles()
34
35     NSOpenPanel *panel;
36     
37     panel = [NSOpenPanel openPanel];        
38     [panel setFloatingPanel:YES];
39     [panel setCanChooseDirectories:YES];
40     [panel setCanChooseFiles:YES];
41     [panel setAllowsMultipleSelection:YES];
42         int i = [panel runModalForTypes:nil];
43         if(i == NSOKButton){
44                 return [panel filenames];
45     }
46     
47     return nil;
48 }    
49
50
51 @implementation myImageObject
52
53 //- (void) dealloc
54 //{
55 //    [_path release];
56 //    [super dealloc];
57 //}
58
59 /* our datasource object is just a filepath representation */
60 - (void) setPath:(NSString *) path
61 {
62     _path = path;
63     flag = NO;
64 }
65
66 - (void)setMoviePath:(NSString*)path
67 {
68     _path = path;
69     flag = YES;
70 }
71
72
73 /* required methods of the IKImageBrowserItem protocol */
74 #pragma mark -
75 #pragma mark item data source protocol
76
77 /* let the image browser knows we use a path representation */
78 - (NSString *)  imageRepresentationType
79 {
80     if(flag)
81         return IKImageBrowserQTMoviePathRepresentationType;
82     else
83         return IKImageBrowserQuickLookPathRepresentationType;
84     //    return IKImageBrowserPathRepresentationType;
85 }
86
87 /* give our representation to the image browser */
88 - (id)  imageRepresentation
89 {
90         return _path;
91 }
92
93 /* use the absolute filepath as identifier */
94 - (NSString *) imageUID
95 {
96     return _path;
97 }
98
99 - (NSString *)imageTitle
100 {
101     return [_path lastPathComponent];
102 }
103
104 @end
105
106
107
108 /* the controller */
109 @implementation ElisMediaBrowserController
110
111 - (void) dealloc
112 {
113     [_images release];
114     [_importedImages release];
115     [super dealloc];
116 }
117
118 - (void) awakeFromNib
119 {
120         /* create two arrays : the first one is our datasource representation, the second one are temporary imported images (for thread safeness ) 
121      */
122     _images = [[NSMutableArray alloc] init];
123     _importedImages = [[NSMutableArray alloc] init];
124     _tempArray = [[NSMutableArray alloc] init];
125     
126     //allow reordering, animations et set draggind destination delegate
127     [_mediaBrowser setAllowsReordering:YES];
128     [_mediaBrowser setAnimates:YES];
129     [_mediaBrowser setDraggingDestinationDelegate:self];
130 //    [_mediaBrowser setBackgroundColor:[NSColor grayColor]];
131     
132     lock = [[NSRecursiveLock alloc] init];
133 }
134
135 /* entry point for reloading image-browser's data and setNeedsDisplay */
136 - (void) updateDatasource
137 {
138     //-- update our datasource, add recently imported items
139     [_images addObjectsFromArray:_importedImages];
140         
141         //-- empty our temporary array
142     [_importedImages removeAllObjects];
143     
144     //-- reload the image browser and set needs display
145     [_mediaBrowser reloadData];
146 }
147
148 #pragma mark -
149 #pragma mark import images from file system
150
151 /* code that parse a repository and add all items in an independant array,
152  When done, call updateDatasource, add these items to our datasource array
153  This code is performed in an independant thread.
154  */
155
156 - (BOOL)canInitQT:(NSString*)path
157 {
158     canRead = [QTMovie canInitWithFile:path];
159 }
160
161 - (void) addAnImageWithPath:(NSString *) path
162 {   
163     myImageObject *p;
164     NSWorkspace* sharedWorkspace = [NSWorkspace sharedWorkspace];
165     
166  
167     
168     // 読めるメディアかチェック
169     if([sharedWorkspace type:[sharedWorkspace typeOfFile:path error:nil] 
170               conformsToType:@"public.image"]) {
171            
172            /* add a path to our temporary array */
173         CIImage* ci = [CIImage imageWithContentsOfURL:[NSURL fileURLWithPath:path]];
174         if(ci == nil) return;
175            p = [[myImageObject alloc] init];
176            [p setPath:path];
177            [_importedImages addObject:p];
178     }
179     else{
180         [lock lock];
181            [self performSelectorOnMainThread:@selector(canInitQT:) withObject:path waitUntilDone:YES];
182         [lock unlock];
183         if(canRead
184 //            [sharedWorkspace type:[sharedWorkspace typeOfFile:path error:nil] 
185 //                   conformsToType:@"public.movie"] ||
186 //            [sharedWorkspace type:[sharedWorkspace typeOfFile:path error:nil] 
187 //                   conformsToType:@"public.audio"] ||
188 //            [sharedWorkspace type:[sharedWorkspace typeOfFile:path error:nil] 
189 //                   conformsToType:@"com.apple.quartz-composer-composition"]
190             )
191     {
192         p = [[myImageObject alloc] init];
193         [p setMoviePath:path];
194         [_importedImages addObject:p];
195     }
196     }
197 }
198
199 - (void) addImagesWithPath:(NSString *) path recursive:(BOOL) recursive
200 {
201     int i, n;
202     BOOL dir;
203     
204     [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&dir];
205     
206     if(dir){
207         NSArray *content = [[NSFileManager defaultManager] directoryContentsAtPath:path];
208         
209         n = [content count];
210         
211                 /* parse the directory content*/
212         for(i=0; i<n; i++){
213             //            NSLog(@"%d", i);
214             if(recursive)
215                 [self addImagesWithPath:[path stringByAppendingPathComponent:[content objectAtIndex:i]] recursive:YES];
216             else
217                 [self addAnImageWithPath:[path stringByAppendingPathComponent:[content objectAtIndex:i]]];
218         }
219     }
220     else
221         [self addAnImageWithPath:path];
222 }
223
224 /* performed in an independant thread, parse all paths in "paths" and add these paths in our temporary array */
225 - (void) addImagesWithPaths:(NSArray *) paths
226 {   
227     int i, n;
228     
229     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
230     
231     n = [paths count];
232     for(i=0; i<n; i++){
233         NSString *path = [paths objectAtIndex:i];
234         [self addImagesWithPath:path recursive:NO];
235     }
236     
237         /* update the datasource in the main thread */
238     [self performSelectorOnMainThread:@selector(updateDatasource) withObject:nil waitUntilDone:YES];
239     
240     _tempArray = [_images copy];
241     
242     [pool release];
243 }
244
245 #pragma mark -
246 #pragma mark actions
247
248 /* "add" button was clicked */
249 - (IBAction) addImageMenuClicked:(id) sender
250 {   
251     NSArray *path = openFiles();
252     
253     if(!path){ 
254         NSLog(@"No path selected, return..."); 
255         return; 
256     }
257         
258         /* launch import in an independent thread */
259     [NSThread detachNewThreadSelector:@selector(addImagesWithPaths:) toTarget:self withObject:path];
260 }
261
262 /* action called when the zoom slider did change */
263 - (IBAction) zoomSliderDidChange:(id)sender
264 {
265         /* update the zoom value to scale images */
266     [_mediaBrowser setZoomValue:[sender floatValue]];
267         
268         /* redisplay */
269     [_mediaBrowser setNeedsDisplay:YES];
270 }
271
272 #pragma mark -
273 #pragma mark IKImageBrowserDataSource
274
275 /* implement image-browser's datasource protocol 
276  Our datasource representation is a simple mutable array
277  */
278
279 - (int) numberOfItemsInImageBrowser:(IKImageBrowserView *) view
280 {
281         /* item count to display is our datasource item count */
282     return [_images count];
283 }
284
285 - (id) imageBrowser:(IKImageBrowserView *) view itemAtIndex:(int) index
286 {
287     return [_images objectAtIndex:index];
288 }
289
290 /* implement some optional methods of the image-browser's datasource protocol to be able to remove and reoder items */
291
292 /*      remove
293  The user wants to delete images, so remove these entries from our datasource.  
294  */
295 - (void) imageBrowser:(IKImageBrowserView *) view removeItemsAtIndexes: (NSIndexSet *) indexes
296 {
297         [_images removeObjectsAtIndexes:indexes];
298 }
299
300 /* reordering 
301  The user wants to reorder images, update our datasource and the browser will reflect our changes
302  */
303 - (BOOL) imageBrowser:(IKImageBrowserView *) view  moveItemsAtIndexes: (NSIndexSet *)indexes toIndex:(unsigned int)destinationIndex
304 {
305     int index;
306     NSMutableArray *temporaryArray;
307     
308     temporaryArray = [[[NSMutableArray alloc] init] autorelease];
309     
310     /* first remove items from the datasource and keep them in a temporary array */
311     for(index=[indexes lastIndex]; index != NSNotFound; index = [indexes indexLessThanIndex:index]){
312         if (index < destinationIndex)
313             destinationIndex --;
314         
315         id obj = [_images objectAtIndex:index];
316         [temporaryArray addObject:obj];
317         [_images removeObjectAtIndex:index];
318     }
319     
320     /* then insert removed items at the good location */
321     int n = [temporaryArray count];
322     for(index=0; index < n; index++){
323         [_images insertObject:[temporaryArray objectAtIndex:index] atIndex:destinationIndex];
324     }
325         
326     return YES;
327 }
328
329 #pragma mark -
330 #pragma mark drag n drop 
331
332 /* Drag'n drop support, accept any kind of drop */
333 - (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender
334 {
335     return NSDragOperationCopy;
336 }
337
338 - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender
339 {
340     return NSDragOperationCopy;
341 }
342
343 - (BOOL) performDragOperation:(id <NSDraggingInfo>)sender
344 {
345     NSData *data = nil;
346     NSString *errorDescription;
347         
348     NSPasteboard *pasteboard = [sender draggingPasteboard];
349     
350         /* look for paths in pasteboard */
351     if ([[pasteboard types] containsObject:NSFilenamesPboardType]) 
352         data = [pasteboard dataForType:NSFilenamesPboardType];
353     
354     if(data){
355                 /* retrieves paths */
356         NSArray *filenames = [NSPropertyListSerialization propertyListFromData:data 
357                                                               mutabilityOption:kCFPropertyListImmutable 
358                                                                         format:nil 
359                                                               errorDescription:&errorDescription];
360         
361         
362                 /* add paths to our datasource */
363         int i;
364         int n = [filenames count];
365         for(i=0; i<n; i++){
366             [self addAnImageWithPath:[filenames objectAtIndex:i]];
367         }
368                 
369                 /* make the image browser reload our datasource */
370         [self updateDatasource];
371     }
372     
373         /* we accepted the drag operation */
374         return YES;
375 }
376
377 - (IBAction)searchFieldUpdate:(id)sender
378 {
379     NSMutableArray* tempArray = [[NSMutableArray alloc] init];
380     NSString* searchString = [sender stringValue];
381         
382     NSRange r;
383     id image;
384     
385     if([searchString length] == 0){
386 //        _importedImages = _tempArray;
387 //        [self updateDatasource];
388         _images = _tempArray;
389         [_mediaBrowser reloadData];
390         return;
391     }
392     
393     for(image in _tempArray){
394         r = [[image imageTitle] rangeOfString:searchString];
395         if(r.length != 0)
396             [_importedImages addObject:image];
397     }
398     
399     [_images removeAllObjects];
400     _images = [_importedImages copy];
401 //    [_importedImages removeAllObjects];
402     [_mediaBrowser reloadData];
403 //    [self updateDatasource];
404     
405 }
406
407 @end
408