Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /XspfQT/XspfQTPlayListWindowController.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 373 - (hide annotations) (download)
Sun Mar 4 01:39:53 2012 UTC (12 years, 1 month ago) by masakih
File size: 13174 byte(s)
[Mod] ライセンスの年を変更

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

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