Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /XspfQT/XspfQTPlayListWindowController.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 312 - (hide annotations) (download)
Sun May 16 02:22:37 2010 UTC (13 years, 11 months ago) by masakih
File size: 12520 byte(s)
著作権表示、免責表示を追加。
1 masaki 2 //
2 masaki 72 // XspfQTPlayListWindowController.m
3 masaki 2 // XspfQT
4     //
5     // Created by Hori,Masaki on 08/08/31.
6     //
7    
8 masakih 312 /*
9     Copyright (c) 2008-2010, masakih
10     All rights reserved.
11     ソースコード形式かバイナリ形式か、変更するかしないかを問わず、以下の条件を満たす場合に限り、再頒布および使用が許可されます。
12    
13     1, ソースコードを再頒布する場合、上記の著作権表示、本条件一覧、および下記免責条項を含めること。
14     2, バイナリ形式で再頒布する場合、頒布物に付属のドキュメント等の資料に、上記の著作権表示、本条件一覧、および下記免責条項を含めること。
15     3, 書面による特別の許可なしに、本ソフトウェアから派生した製品の宣伝または販売促進に、コントリビューターの名前を使用してはならない。
16     本ソフトウェアは、著作権者およびコントリビューターによって「現状のまま」提供されており、明示黙示を問わず、商業的な使用可能性、および特定の目的に対する適合性に関する暗黙の保証も含め、またそれに限定されない、いかなる保証もありません。著作権者もコントリビューターも、事由のいかんを問わず、 損害発生の原因いかんを問わず、かつ責任の根拠が契約であるか厳格責任であるか(過失その他の)不法行為であるかを問わず、仮にそのような損害が発生する可能性を知らされていたとしても、本ソフトウェアの使用によって発生した(代替品または代用サービスの調達、使用の喪失、データの喪失、利益の喪失、業務の中断も含め、またそれに限定されない)直接損害、間接損害、偶発的な損害、特別損害、懲罰的損害、または結果損害について、一切責任を負わないものとします。
17     -------------------------------------------------------------------
18     Copyright (c) 2008-2010, masakih
19     All rights reserved.
20    
21     Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
22    
23     1, Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
24     2, Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
25     3, The names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
26     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27     */
28    
29 masaki 72 #import "XspfQTPlayListWindowController.h"
30     #import "XspfQTDocument.h"
31 masaki 306 #import "HMXSPFComponent.h"
32 masaki 2
33 masaki 290 #import "BSSUtil.h"
34 masaki 2
35 masaki 290
36 masaki 72 @interface XspfQTPlayListWindowController(Private)
37 masaki 41 - (void)setObserveObject:(id)new;
38 masaki 96
39 masaki 290 - (NSString *)clickedMoviePath;
40    
41 masaki 96 - (void)insertItem:(id)item atIndex:(NSUInteger)index;
42     - (void)removeItem:(id)item;
43     - (void)moveItem:(id)item toIndex:(NSUInteger)index;
44     - (void)insertItemFromURL:(id)item atIndex:(NSUInteger)index;
45 masaki 41 @end
46    
47 masaki 72 @implementation XspfQTPlayListWindowController
48 masaki 2
49 masaki 111 #pragma mark ### Static variables ###
50 masaki 53 static NSString *const XspfQTPlayListItemType = @"XspfQTPlayListItemType";
51    
52 masaki 244 static NSString *const XspfQTTitleKey = @"title";
53    
54 masaki 2 - (id)init
55     {
56 masaki 73 return [super initWithWindowNibName:@"XspfQTPlayList"];
57 masaki 2 }
58 masaki 111 - (void)dealloc
59     {
60     [trackListTree removeObserver:self forKeyPath:@"selection"];
61     [self setObserveObject:nil];
62    
63     [super dealloc];
64     }
65 masaki 2
66     - (void)awakeFromNib
67     {
68     [listView setDoubleAction:@selector(changeCurrentTrack:)];
69 masaki 41 [[self window] setReleasedWhenClosed:NO];
70    
71     [trackListTree addObserver:self
72     forKeyPath:@"selection"
73     options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
74     context:NULL];
75     [self setObserveObject:[trackListTree valueForKeyPath:@"selection.self"]];
76 masaki 51
77     [listView expandItem:[listView itemAtRow:0]];
78 masaki 53
79 masaki 90 [listView registerForDraggedTypes:[NSArray arrayWithObjects:
80     XspfQTPlayListItemType,
81     NSFilenamesPboardType,
82     NSURLPboardType,
83     nil]];
84 masaki 2 }
85    
86 masaki 111 #pragma mark ### Actions ###
87 masaki 2 - (IBAction)changeCurrentTrack:(id)sender
88     {
89     id selections = [trackListTree selectedObjects];
90     if([selections count] == 0) return;
91    
92     NSIndexPath *selectionIndexPath = [trackListTree selectionIndexPath];
93    
94     if([selectionIndexPath length] > 1) {
95 masaki 177 [[[self document] trackList] setSelectionIndex:[selectionIndexPath indexAtPosition:1]];
96 masaki 2 }
97     }
98 masaki 84 - (IBAction)delete:(id)sender
99     {
100     id selection = [trackListTree valueForKeyPath:@"selection.self"];
101 masaki 96 [self removeItem:selection];
102 masaki 290 }
103 masaki 296 - (IBAction)showInFinder:(id)sender
104 masaki 290 {
105     NSString *path = [self clickedMoviePath];
106     if(path) {
107     openInFinderWithPath(path);
108     }
109 masaki 84 }
110 masaki 296 - (IBAction)showInformationInFinder:(id)sender
111 masaki 290 {
112     NSString *path = [self clickedMoviePath];
113     if(path) {
114     openInfomationInFinderWithPath(path);
115     }
116     }
117    
118 masaki 34 - (void)keyDown:(NSEvent *)theEvent
119     {
120     if([theEvent isARepeat]) return;
121    
122     unsigned short code = [theEvent keyCode];
123     if(code == 49 /* space bar */) {
124     [[self document] togglePlayAndPause:self];
125     }
126 masaki 83 if(code == 51 /* delete key */) {
127 masaki 84 [self delete:self];
128 masaki 83 }
129 masaki 34 }
130 masaki 290 - (NSString *)clickedMoviePath
131     {
132     int row = [listView clickedRow];
133     id item = [listView itemAtRow:row];
134     if(!item) return nil;
135    
136     NSURL *location = [[item representedObject] movieLocation];
137     NSString *result = [location path];
138    
139     return result;
140     }
141 masaki 34
142 masaki 84 #pragma mark ### NSMenu valivation ###
143     - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
144     {
145 masaki 290 SEL action = [menuItem action];
146     if(action == @selector(delete:)) {
147 masaki 84 if([[trackListTree selectedObjects] count] == 0) {
148     return NO;
149     }
150     if(![[trackListTree valueForKeyPath:@"selection.isLeaf"] boolValue]) {
151     return NO;
152     }
153     }
154 masaki 296 if(action == @selector(showInFinder:) || action == @selector(showInformationInFinder:)) {
155 masaki 290 NSString *path = [self clickedMoviePath];
156     if(!path) return NO;
157     }
158 masaki 84
159     return YES;
160     }
161    
162 masaki 111 #pragma mark ### NSWindow Delegate ###
163 masaki 2 - (BOOL)windowShouldClose:(id)sender
164     {
165     [sender orderOut:self];
166    
167     return NO;
168     }
169 masaki 111
170     #pragma mark ### KVO & KVC ###
171 masaki 41 - (void)setObserveObject:(id)new
172     {
173 masaki 111 if(observedObject == new) return;
174 masaki 41
175 masaki 244 [observedObject removeObserver:self forKeyPath:XspfQTTitleKey];
176 masaki 41
177 masaki 111 observedObject = new;
178     [observedObject addObserver:self
179 masaki 244 forKeyPath:XspfQTTitleKey
180 masaki 41 options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
181     context:NULL];
182     }
183     - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
184     {
185 masaki 49 if([keyPath isEqualToString:@"selection"]) {
186 masaki 41 id new = [object valueForKeyPath:@"selection.self"];
187     [self setObserveObject:new];
188     }
189    
190 masaki 244 if([keyPath isEqualToString:XspfQTTitleKey]) {
191 masaki 41 id new = [change objectForKey:NSKeyValueChangeNewKey];
192     id old = [change objectForKey:NSKeyValueChangeOldKey];
193    
194     if(new == old) return;
195     if([new isEqualTo:old]) return;
196    
197     id um = [[self document] undoManager];
198 masaki 111 [um registerUndoWithTarget:observedObject
199 masaki 41 selector:@selector(setTitle:)
200     object:old];
201     }
202     }
203 masaki 2
204 masaki 111 #pragma mark ### DataStructure Operations ###
205 masaki 96 - (void)insertItemFromURL:(id)item atIndex:(NSUInteger)index
206     {
207     id doc = [self document];
208     [doc insertComponentFromURL:item atIndex:index];
209     }
210     - (void)insertItem:(id)item atIndex:(NSUInteger)index
211     {
212     id doc = [self document];
213     [doc insertComponent:item atIndex:index];
214     }
215     - (void)removeItem:(id)item
216     {
217     id doc = [self document];
218     [doc removeComponent:item];
219     }
220     - (void)moveItem:(id)item toIndex:(NSUInteger)index
221     {
222     id doc = [self document];
223 masaki 248 [doc moveComponent:item toIndex:index];
224 masaki 96 }
225    
226 masaki 90 - (void)insertItemURL:(NSURL *)url atIndex:(NSUInteger)index
227     {
228     if(![QTMovie canInitWithURL:url]) {
229     @throw self;
230     }
231    
232     @try {
233 masaki 96 [self insertItemFromURL:url atIndex:index];
234 masaki 90 }
235     @catch(XspfQTDocument *doc) {
236     @throw self;
237     }
238     }
239     - (BOOL)canInsertItemFromPasteboard:(NSPasteboard *)pb
240     {
241     if([[pb types] containsObject:NSFilenamesPboardType] ||
242     [[pb types] containsObject:NSURLPboardType]) {
243    
244     // ##### Check is playable. #####
245     if([QTMovie canInitWithPasteboard:pb]) {
246     return YES;
247     }
248     }
249    
250     return NO;
251     }
252     - (void)insertItemFromPasteboard:(NSPasteboard *)pb atIndex:(NSUInteger)index
253     {
254     // check filenames.
255     if([[pb types] containsObject:NSFilenamesPboardType]) {
256     BOOL hasSuccesItem = NO;
257    
258     id plist = [pb propertyListForType:NSFilenamesPboardType];
259     if(![plist isKindOfClass:[NSArray class]]) {
260     @throw self;
261     }
262     NSEnumerator *reverse = [plist reverseObjectEnumerator];
263     for(id obj in reverse) {
264     NSURL *fileURL = [NSURL fileURLWithPath:obj];
265     @try {
266     [self insertItemURL:fileURL atIndex:index];
267     }
268     @catch(XspfQTPlayListWindowController *me) {
269     continue;
270     }
271     hasSuccesItem = YES;
272     }
273    
274     if(!hasSuccesItem) {
275     @throw self;
276     }
277     return;
278     }
279    
280     // check URL
281     if([[pb types] containsObject:NSURLPboardType]) {
282     id url = [NSURL URLFromPasteboard:pb];
283     if(url) {
284     [self insertItemURL:url atIndex:index];
285     return;
286     }
287     }
288    
289     @throw self;
290     }
291 masaki 53
292 masaki 111 #pragma mark ### NSOutlineView DataSource ###
293 masaki 53 - (BOOL)outlineView:(NSOutlineView *)outlineView
294     writeItems:(NSArray *)items
295     toPasteboard:(NSPasteboard *)pasteboard
296     {
297     if([items count] > 1) return NO;
298    
299     id item = [[items objectAtIndex:0] representedObject];
300    
301 masaki 306 if(![item isKindOfClass:[HMXSPFComponent class]]) {
302 masaki 53 NSLog(@"Ouch! %@", NSStringFromClass([item class]));
303     return NO;
304     }
305     if(![item isLeaf]) return NO;
306    
307     NSData *data = [NSKeyedArchiver archivedDataWithRootObject:item];
308     if(!data) {
309     NSLog(@"Could not archive.");
310     return NO;
311     }
312    
313     [pasteboard declareTypes:[NSArray arrayWithObject:XspfQTPlayListItemType]
314 masaki 139 owner:nil];
315 masaki 53 [pasteboard setData:data
316     forType:XspfQTPlayListItemType];
317     return YES;
318     }
319     - (NSDragOperation)outlineView:(NSOutlineView *)outlineView
320     validateDrop:(id <NSDraggingInfo>)info
321     proposedItem:(id)item
322     proposedChildIndex:(NSInteger)index
323     {
324     if([item isLeaf]) {
325     return NSDragOperationNone;
326     }
327    
328     id pb = [info draggingPasteboard];
329    
330     if(![[pb types] containsObject:XspfQTPlayListItemType]) {
331 masaki 88 // ##### insert files? #####
332 masaki 90 if([self canInsertItemFromPasteboard:pb]) {
333     return NSDragOperationCopy;
334     }
335 masaki 53 return NSDragOperationNone;
336     }
337    
338 masaki 80 if(index == -1) return NSDragOperationNone;
339    
340 masaki 53 return NSDragOperationMove;
341     }
342     - (BOOL)outlineView:(NSOutlineView *)outlineView
343     acceptDrop:(id <NSDraggingInfo>)info
344     item:(id)item
345     childIndex:(NSInteger)index
346     {
347     if([item isLeaf]) {
348     return NO;
349     }
350    
351 masaki 98 if(index == -1) {
352     index = [[[self document] trackList] childrenCount];
353     }
354    
355 masaki 53 id pb = [info draggingPasteboard];
356    
357     NSData *data = [pb dataForType:XspfQTPlayListItemType];
358 masaki 88 if(!data) {
359 masaki 90 // ##### insert files? #####
360     @try {
361     [self insertItemFromPasteboard:pb atIndex:index];
362     }
363     @catch(XspfQTPlayListWindowController *me) {
364     return NO;
365     }
366     return YES;
367 masaki 88 }
368 masaki 53
369     id newItem = [NSKeyedUnarchiver unarchiveObjectWithData:data];
370     if(!newItem) return NO;
371    
372 masaki 80 id doc = [self document];
373     NSInteger oldIndex = [[doc trackList] indexOfChild:newItem];
374 masaki 53
375 masaki 88 if(oldIndex == NSNotFound) {
376     // from other list.
377 masaki 96 [self insertItem:newItem atIndex:index];
378 masaki 88 return YES;
379     }
380    
381 masaki 80 if(oldIndex == index) return YES;
382     if(oldIndex < index) {
383     index--;
384     }
385    
386     // change archive to original.
387     newItem = [[doc trackList] childAtIndex:oldIndex];
388    
389     BOOL mustSelectionChange = NO;
390     if([newItem isSelected]) {
391     mustSelectionChange = YES;
392     }
393    
394 masaki 96 [self moveItem:newItem toIndex:index];
395 masaki 80
396     if(mustSelectionChange) {
397 masaki 177 [[doc trackList] setSelectionIndex:index];
398 masaki 80 }
399    
400 masaki 59 return YES;
401 masaki 53 }
402    
403 masaki 2 @end
404 masaki 34
405 masaki 126 @implementation XspfQTPlaylistOutlineView
406 masaki 34 - (void)keyDown:(NSEvent *)theEvent
407     {
408 masaki 83 if(_delegate && [_delegate respondsToSelector:@selector(keyDown:)]) {
409     [_delegate keyDown:theEvent];
410 masaki 34 }
411    
412     [super keyDown:theEvent];
413     }
414     @end

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26