Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /XspfQT/XspfQTPlayListWindowController.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 349 - (hide annotations) (download)
Tue Jun 28 14:11:49 2011 UTC (12 years, 9 months ago) by masakih
File size: 12943 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 312 Copyright (c) 2008-2010, masakih
11     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     Copyright (c) 2008-2010, masakih
33     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 masaki 290
69 masaki 72 @interface XspfQTPlayListWindowController(Private)
70 masaki 41 - (void)setObserveObject:(id)new;
71 masaki 96
72 masaki 290 - (NSString *)clickedMoviePath;
73    
74 masaki 96 - (void)insertItem:(id)item atIndex:(NSUInteger)index;
75     - (void)removeItem:(id)item;
76     - (void)moveItem:(id)item toIndex:(NSUInteger)index;
77     - (void)insertItemFromURL:(id)item atIndex:(NSUInteger)index;
78 masaki 41 @end
79    
80 masaki 72 @implementation XspfQTPlayListWindowController
81 masaki 2
82 masaki 111 #pragma mark ### Static variables ###
83 masaki 53 static NSString *const XspfQTPlayListItemType = @"XspfQTPlayListItemType";
84    
85 masaki 244 static NSString *const XspfQTTitleKey = @"title";
86    
87 masaki 2 - (id)init
88     {
89 masaki 73 return [super initWithWindowNibName:@"XspfQTPlayList"];
90 masaki 2 }
91 masaki 111 - (void)dealloc
92     {
93     [trackListTree removeObserver:self forKeyPath:@"selection"];
94     [self setObserveObject:nil];
95    
96     [super dealloc];
97     }
98 masaki 2
99     - (void)awakeFromNib
100     {
101     [listView setDoubleAction:@selector(changeCurrentTrack:)];
102 masaki 41 [[self window] setReleasedWhenClosed:NO];
103    
104     [trackListTree addObserver:self
105     forKeyPath:@"selection"
106     options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
107     context:NULL];
108     [self setObserveObject:[trackListTree valueForKeyPath:@"selection.self"]];
109 masaki 51
110     [listView expandItem:[listView itemAtRow:0]];
111 masaki 53
112 masaki 90 [listView registerForDraggedTypes:[NSArray arrayWithObjects:
113     XspfQTPlayListItemType,
114     NSFilenamesPboardType,
115     NSURLPboardType,
116     nil]];
117 masaki 2 }
118    
119 masaki 111 #pragma mark ### Actions ###
120 masaki 2 - (IBAction)changeCurrentTrack:(id)sender
121     {
122     id selections = [trackListTree selectedObjects];
123     if([selections count] == 0) return;
124    
125     NSIndexPath *selectionIndexPath = [trackListTree selectionIndexPath];
126    
127     if([selectionIndexPath length] > 1) {
128 masaki 177 [[[self document] trackList] setSelectionIndex:[selectionIndexPath indexAtPosition:1]];
129 masaki 2 }
130     }
131 masaki 84 - (IBAction)delete:(id)sender
132     {
133     id selection = [trackListTree valueForKeyPath:@"selection.self"];
134 masaki 96 [self removeItem:selection];
135 masaki 290 }
136 masaki 296 - (IBAction)showInFinder:(id)sender
137 masaki 290 {
138     NSString *path = [self clickedMoviePath];
139     if(path) {
140     openInFinderWithPath(path);
141     }
142 masaki 84 }
143 masaki 296 - (IBAction)showInformationInFinder:(id)sender
144 masaki 290 {
145     NSString *path = [self clickedMoviePath];
146     if(path) {
147     openInfomationInFinderWithPath(path);
148     }
149     }
150 masakih 322 - (IBAction)showHideWindow:(id)sender
151     {
152     NSWindow *window = [self window];
153     if([window isVisible]) {
154     [window performClose:sender];
155     } else {
156     [self showWindow:self];
157     }
158     }
159 masaki 290
160 masaki 34 - (void)keyDown:(NSEvent *)theEvent
161     {
162     if([theEvent isARepeat]) return;
163    
164 masakih 349 NSString *charactor = [theEvent charactersIgnoringModifiers];
165     if([charactor length] == 0) return;
166    
167     unichar uc = [charactor characterAtIndex:0];
168     switch(uc) {
169     case ' ':
170     [NSApp sendAction:@selector(togglePlayAndPause:) to:nil from:nil];
171     break;
172     case NSDeleteCharacter:
173     [self delete:self];
174     break;
175 masaki 34 }
176     }
177 masaki 290 - (NSString *)clickedMoviePath
178     {
179     int row = [listView clickedRow];
180     id item = [listView itemAtRow:row];
181     if(!item) return nil;
182    
183     NSURL *location = [[item representedObject] movieLocation];
184     NSString *result = [location path];
185    
186     return result;
187     }
188 masaki 34
189 masaki 84 #pragma mark ### NSMenu valivation ###
190     - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
191     {
192 masaki 290 SEL action = [menuItem action];
193     if(action == @selector(delete:)) {
194 masaki 84 if([[trackListTree selectedObjects] count] == 0) {
195     return NO;
196     }
197     if(![[trackListTree valueForKeyPath:@"selection.isLeaf"] boolValue]) {
198     return NO;
199     }
200     }
201 masaki 296 if(action == @selector(showInFinder:) || action == @selector(showInformationInFinder:)) {
202 masaki 290 NSString *path = [self clickedMoviePath];
203     if(!path) return NO;
204     }
205 masaki 84
206     return YES;
207     }
208    
209 masaki 111 #pragma mark ### NSWindow Delegate ###
210 masaki 2 - (BOOL)windowShouldClose:(id)sender
211     {
212     [sender orderOut:self];
213    
214     return NO;
215     }
216 masaki 111
217     #pragma mark ### KVO & KVC ###
218 masaki 41 - (void)setObserveObject:(id)new
219     {
220 masaki 111 if(observedObject == new) return;
221 masaki 41
222 masaki 244 [observedObject removeObserver:self forKeyPath:XspfQTTitleKey];
223 masaki 41
224 masaki 111 observedObject = new;
225     [observedObject addObserver:self
226 masaki 244 forKeyPath:XspfQTTitleKey
227 masaki 41 options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
228     context:NULL];
229     }
230     - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
231     {
232 masaki 49 if([keyPath isEqualToString:@"selection"]) {
233 masaki 41 id new = [object valueForKeyPath:@"selection.self"];
234     [self setObserveObject:new];
235     }
236    
237 masaki 244 if([keyPath isEqualToString:XspfQTTitleKey]) {
238 masaki 41 id new = [change objectForKey:NSKeyValueChangeNewKey];
239     id old = [change objectForKey:NSKeyValueChangeOldKey];
240    
241     if(new == old) return;
242     if([new isEqualTo:old]) return;
243    
244     id um = [[self document] undoManager];
245 masaki 111 [um registerUndoWithTarget:observedObject
246 masaki 41 selector:@selector(setTitle:)
247     object:old];
248     }
249     }
250 masaki 2
251 masaki 111 #pragma mark ### DataStructure Operations ###
252 masaki 96 - (void)insertItemFromURL:(id)item atIndex:(NSUInteger)index
253     {
254     id doc = [self document];
255     [doc insertComponentFromURL:item atIndex:index];
256     }
257     - (void)insertItem:(id)item atIndex:(NSUInteger)index
258     {
259     id doc = [self document];
260     [doc insertComponent:item atIndex:index];
261     }
262     - (void)removeItem:(id)item
263     {
264     id doc = [self document];
265     [doc removeComponent:item];
266     }
267     - (void)moveItem:(id)item toIndex:(NSUInteger)index
268     {
269     id doc = [self document];
270 masaki 248 [doc moveComponent:item toIndex:index];
271 masaki 96 }
272    
273 masaki 90 - (void)insertItemURL:(NSURL *)url atIndex:(NSUInteger)index
274     {
275     if(![QTMovie canInitWithURL:url]) {
276     @throw self;
277     }
278    
279     @try {
280 masaki 96 [self insertItemFromURL:url atIndex:index];
281 masaki 90 }
282     @catch(XspfQTDocument *doc) {
283     @throw self;
284     }
285     }
286     - (BOOL)canInsertItemFromPasteboard:(NSPasteboard *)pb
287     {
288     if([[pb types] containsObject:NSFilenamesPboardType] ||
289     [[pb types] containsObject:NSURLPboardType]) {
290    
291     // ##### Check is playable. #####
292     if([QTMovie canInitWithPasteboard:pb]) {
293     return YES;
294     }
295     }
296    
297     return NO;
298     }
299     - (void)insertItemFromPasteboard:(NSPasteboard *)pb atIndex:(NSUInteger)index
300     {
301     // check filenames.
302     if([[pb types] containsObject:NSFilenamesPboardType]) {
303     BOOL hasSuccesItem = NO;
304    
305     id plist = [pb propertyListForType:NSFilenamesPboardType];
306     if(![plist isKindOfClass:[NSArray class]]) {
307     @throw self;
308     }
309     NSEnumerator *reverse = [plist reverseObjectEnumerator];
310     for(id obj in reverse) {
311     NSURL *fileURL = [NSURL fileURLWithPath:obj];
312     @try {
313     [self insertItemURL:fileURL atIndex:index];
314     }
315     @catch(XspfQTPlayListWindowController *me) {
316     continue;
317     }
318     hasSuccesItem = YES;
319     }
320    
321     if(!hasSuccesItem) {
322     @throw self;
323     }
324     return;
325     }
326    
327     // check URL
328     if([[pb types] containsObject:NSURLPboardType]) {
329     id url = [NSURL URLFromPasteboard:pb];
330     if(url) {
331     [self insertItemURL:url atIndex:index];
332     return;
333     }
334     }
335    
336     @throw self;
337     }
338 masaki 53
339 masaki 111 #pragma mark ### NSOutlineView DataSource ###
340 masaki 53 - (BOOL)outlineView:(NSOutlineView *)outlineView
341     writeItems:(NSArray *)items
342     toPasteboard:(NSPasteboard *)pasteboard
343     {
344     if([items count] > 1) return NO;
345    
346     id item = [[items objectAtIndex:0] representedObject];
347    
348 masaki 306 if(![item isKindOfClass:[HMXSPFComponent class]]) {
349 masaki 53 NSLog(@"Ouch! %@", NSStringFromClass([item class]));
350     return NO;
351     }
352     if(![item isLeaf]) return NO;
353    
354     NSData *data = [NSKeyedArchiver archivedDataWithRootObject:item];
355     if(!data) {
356     NSLog(@"Could not archive.");
357     return NO;
358     }
359    
360     [pasteboard declareTypes:[NSArray arrayWithObject:XspfQTPlayListItemType]
361 masaki 139 owner:nil];
362 masaki 53 [pasteboard setData:data
363     forType:XspfQTPlayListItemType];
364     return YES;
365     }
366     - (NSDragOperation)outlineView:(NSOutlineView *)outlineView
367     validateDrop:(id <NSDraggingInfo>)info
368     proposedItem:(id)item
369     proposedChildIndex:(NSInteger)index
370     {
371     if([item isLeaf]) {
372     return NSDragOperationNone;
373     }
374    
375     id pb = [info draggingPasteboard];
376    
377     if(![[pb types] containsObject:XspfQTPlayListItemType]) {
378 masaki 88 // ##### insert files? #####
379 masaki 90 if([self canInsertItemFromPasteboard:pb]) {
380     return NSDragOperationCopy;
381     }
382 masaki 53 return NSDragOperationNone;
383     }
384    
385 masaki 80 if(index == -1) return NSDragOperationNone;
386    
387 masaki 53 return NSDragOperationMove;
388     }
389     - (BOOL)outlineView:(NSOutlineView *)outlineView
390     acceptDrop:(id <NSDraggingInfo>)info
391     item:(id)item
392     childIndex:(NSInteger)index
393     {
394     if([item isLeaf]) {
395     return NO;
396     }
397    
398 masaki 98 if(index == -1) {
399     index = [[[self document] trackList] childrenCount];
400     }
401    
402 masaki 53 id pb = [info draggingPasteboard];
403    
404     NSData *data = [pb dataForType:XspfQTPlayListItemType];
405 masaki 88 if(!data) {
406 masaki 90 // ##### insert files? #####
407     @try {
408     [self insertItemFromPasteboard:pb atIndex:index];
409     }
410     @catch(XspfQTPlayListWindowController *me) {
411     return NO;
412     }
413     return YES;
414 masaki 88 }
415 masaki 53
416     id newItem = [NSKeyedUnarchiver unarchiveObjectWithData:data];
417     if(!newItem) return NO;
418    
419 masaki 80 id doc = [self document];
420     NSInteger oldIndex = [[doc trackList] indexOfChild:newItem];
421 masaki 53
422 masaki 88 if(oldIndex == NSNotFound) {
423     // from other list.
424 masaki 96 [self insertItem:newItem atIndex:index];
425 masaki 88 return YES;
426     }
427    
428 masaki 80 if(oldIndex == index) return YES;
429     if(oldIndex < index) {
430     index--;
431     }
432    
433     // change archive to original.
434     newItem = [[doc trackList] childAtIndex:oldIndex];
435    
436     BOOL mustSelectionChange = NO;
437     if([newItem isSelected]) {
438     mustSelectionChange = YES;
439     }
440    
441 masaki 96 [self moveItem:newItem toIndex:index];
442 masaki 80
443     if(mustSelectionChange) {
444 masaki 177 [[doc trackList] setSelectionIndex:index];
445 masaki 80 }
446    
447 masaki 59 return YES;
448 masaki 53 }
449    
450 masaki 2 @end
451 masaki 34
452 masaki 126 @implementation XspfQTPlaylistOutlineView
453 masaki 34 - (void)keyDown:(NSEvent *)theEvent
454     {
455 masaki 83 if(_delegate && [_delegate respondsToSelector:@selector(keyDown:)]) {
456     [_delegate keyDown:theEvent];
457 masaki 34 }
458    
459     [super keyDown:theEvent];
460     }
461     @end

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