Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /XspfQT/XspfQTDocument.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 329 - (hide annotations) (download)
Sat Jun 5 15:15:48 2010 UTC (13 years, 10 months ago) by masakih
File size: 16017 byte(s)
コミットする場所を間違えていたので修正。
1 masaki 2 //
2 masaki 72 // XspfQTDocument.m
3 masaki 2 // XspfQT
4     //
5     // Created by Hori,Masaki on 08/08/29.
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 "XspfQTDocument.h"
63 masaki 202 #import "XspfQTAppDelegate.h"
64 masaki 205 #import "XspfQTPreference.h"
65 masaki 306 #import "HMXSPFComponent.h"
66 masaki 72 #import "XspfQTMovieWindowController.h"
67     #import "XspfQTPlayListWindowController.h"
68 masaki 171 #import <QTKit/QTKit.h>
69 masaki 2
70 masaki 306 #import "NSURL-HMExtensions.h"
71 masaki 181 #import "XspfQTMovieLoader.h"
72 masaki 269 #import "XspfQTValueTransformers.h"
73 masaki 181
74 masaki 298 #import "XspfQTMovieTimer.h"
75 masaki 207
76 masaki 298
77 masaki 207 #pragma mark #### Global Variables ####
78     /********* Global variables *******/
79     NSString *XspfQTDocumentWillCloseNotification = @"XspfQTDocumentWillCloseNotification";
80    
81     /**********************************/
82    
83 masaki 72 @interface XspfQTDocument (Private)
84 masaki 306 - (void)setPlaylist:(HMXSPFComponent *)newList;
85     - (HMXSPFComponent *)playlist;
86 masaki 31 - (NSXMLDocument *)XMLDocument;
87 masaki 173 - (void)setPlayingMovie:(QTMovie *)newMovie;
88 masaki 141 - (NSData *)dataFromURL:(NSURL *)url error:(NSError **)outError;
89 masaki 274
90     inline static BOOL isXspfFileType(NSString *typeName);
91     inline static BOOL isReadableMovieType(NSString *typeName);
92 masaki 2 @end
93    
94 masaki 207 static NSString *XspfDocumentType = @"XML Shareable Playlist Format";
95     static NSString *QuickTimeMovieDocumentType = @"QuickTime Movie";
96     static NSString *MatroskaVideoDocumentType = @"Matroska Video";
97     static NSString *DivXMediaFormatDocumentType = @"DivX Media Format";
98    
99 masaki 224 static NSString *XspfUTI = @"com.masakih.xspf";
100    
101 masaki 244 static NSString *XspfQTCurrentTrackKey = @"currentTrack";
102    
103 masaki 72 @implementation XspfQTDocument
104 masaki 2
105 masaki 298 static XspfQTMovieTimer* timer = nil;
106     + (void)initialize
107     {
108     timer = [[XspfQTMovieTimer movieTimer] retain];
109     }
110    
111 masaki 182 - (id)init
112     {
113     self = [super init];
114     if(self) {
115     loader = [[XspfQTMovieLoader loaderWithMovieURL:nil delegate:nil] retain];
116     }
117    
118     return self;
119     }
120 masaki 95 - (id)initWithType:(NSString *)typeName error:(NSError **)outError
121     {
122     [self init];
123    
124 masaki 306 id newPlaylist = [HMXSPFComponent xspfPlaylist];
125 masaki 116 if(!newPlaylist) {
126 masaki 95 [self autorelease];
127     return nil;
128     }
129    
130 masaki 116 [self setPlaylist:newPlaylist];
131 masaki 95
132     return self;
133     }
134 masaki 182 - (void)dealloc
135     {
136     [self setPlayingMovie:nil];
137     [self setPlaylist:nil];
138     [playListWindowController release];
139     [movieWindowController release];
140     [loader release];
141    
142     [super dealloc];
143     }
144 masaki 2
145     - (void)makeWindowControllers
146     {
147 masaki 72 playListWindowController = [[XspfQTPlayListWindowController alloc] init];
148 masaki 2 [self addWindowController:playListWindowController];
149    
150 masaki 72 movieWindowController = [[XspfQTMovieWindowController alloc] init];
151 masaki 42 [movieWindowController setShouldCloseDocument:YES];
152 masaki 2 [self addWindowController:movieWindowController];
153 masaki 298
154     [timer put:self];
155 masaki 2 }
156    
157     - (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
158     {
159 masaki 243 return [[self XMLDocument] XMLDataWithOptions:NSXMLNodePrettyPrint];
160 masaki 2 }
161    
162 masaki 141 - (BOOL)readFromURL:(NSURL *)absoluteURL ofType:(NSString *)typeName error:(NSError **)outError
163     {
164 masaki 274 if(!isReadableMovieType(typeName)) {
165 masaki 141 NSData *data = [self dataFromURL:absoluteURL error:outError];
166     if(!data) return NO;
167    
168     return [self readFromData:data ofType:typeName error:outError];
169     }
170    
171 masaki 306 id new = [HMXSPFComponent xspfTrackWithLocation:absoluteURL];
172 masaki 279 if(!new) {
173 masaki 141 if(outError) {
174 masaki 279 *outError = [NSError errorWithDomain:@"XspfQTErrorDomain" code:1 userInfo:nil];
175 masaki 141 }
176     return NO;
177     }
178    
179 masaki 306 id pl = [HMXSPFComponent xspfPlaylist];
180 masaki 141 if(!pl) {
181     return NO;
182     }
183    
184     [[[pl children] objectAtIndex:0] addChild:new];
185    
186     [self setPlaylist:pl];
187     id t = [self trackList];
188     if(![t title]) {
189     [t setTitle:[[[self fileURL] path] lastPathComponent]];
190     }
191    
192 masaki 207 [self setFileType:XspfDocumentType];
193 masaki 141 [self setFileURL:nil];
194    
195     return YES;
196     }
197 masaki 2 - (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
198     {
199 masaki 274 if(!isXspfFileType(typeName)) {
200 masaki 141 return NO;
201     }
202    
203 masaki 2 NSError *error = nil;
204 masaki 10 NSXMLDocument *d = [[[NSXMLDocument alloc] initWithData:data
205     options:0
206     error:&error] autorelease];
207 masaki 121 if(error) {
208     NSLog(@"%@", error);
209 masaki 272 if(outError) {
210     *outError = error;
211     }
212 masaki 121 return NO;
213     }
214 masaki 2 NSXMLElement *root = [d rootElement];
215 masakih 320 id pl = [HMXSPFComponent xspfComponentWithXMLElement:root];
216 masaki 121 if(!pl) {
217 masaki 306 NSLog(@"Can not create HMXSPFComponent.");
218 masaki 121 return NO;
219     }
220 masaki 116 [self setPlaylist:pl];
221 masaki 2
222 masaki 116 id t = [self trackList];
223 masaki 39 if(![t title]) {
224 masaki 165 [t setTitle:[[[[self fileURL] path] lastPathComponent] stringByDeletingPathExtension]];
225 masaki 39 }
226 masaki 272
227 masaki 2 return YES;
228     }
229    
230 masaki 42 - (void)close
231     {
232 masaki 61 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
233 masaki 72 [nc postNotificationName:XspfQTDocumentWillCloseNotification object:self];
234 masaki 61
235 masaki 42 [self removeWindowController:playListWindowController];
236     [playListWindowController release];
237     playListWindowController = nil;
238    
239     [self removeWindowController:movieWindowController];
240     [movieWindowController release];
241     movieWindowController = nil;
242 masakih 329
243 masaki 42 [super close];
244     }
245    
246 masaki 269 #pragma mark### Actions ###
247 masaki 33 - (IBAction)togglePlayAndPause:(id)sender
248     {
249     [movieWindowController togglePlayAndPause:sender];
250     }
251 masaki 2 - (IBAction)showPlayList:(id)sender
252     {
253     [playListWindowController showWindow:self];
254     }
255 masakih 322 - (IBAction)showHidePlayList:(id)sender
256     {
257     [playListWindowController showHideWindow:self];
258     }
259 masaki 281 - (IBAction)setThumbnailFrame:(id)sender
260 masaki 269 {
261 masaki 306 HMXSPFComponent *currentTrack = [[self trackList] currentTrack];
262 masaki 269 QTTime currentQTTime = [playingMovie currentTime];
263    
264     NSTimeInterval currentTI;
265     QTGetTimeInterval(currentQTTime, &currentTI);
266    
267 masaki 306 HMXSPFComponent *prevThumbnailTrack = [playlist thumbnailTrack];
268 masaki 281 NSTimeInterval ti = [playlist thumbnailTimeInterval];
269 masaki 269
270 masaki 281 [playlist setThumbnailComponent:currentTrack timeIntarval:currentTI];
271 masaki 269
272     id undo = [self undoManager];
273 masaki 281 if(prevThumbnailTrack) {
274     [[undo prepareWithInvocationTarget:playlist] setThumbnailComponent:prevThumbnailTrack timeIntarval:ti];
275     [undo setActionName:NSLocalizedString(@"Change Thumbnail frame.", @"Undo Action Name Change Thumbnail frame")];
276 masaki 269 } else {
277 masaki 281 [[undo prepareWithInvocationTarget:playlist] removeThumbnailFrame];
278     [undo setActionName:NSLocalizedString(@"Add Thumbnail frame.", @"Undo Action Name Add Thumbnail frame")];
279 masaki 269 }
280     }
281 masaki 281 - (IBAction)removeThumbnail:(id)sender
282 masaki 269 {
283 masaki 306 HMXSPFComponent *prevThumbnailTrack = [playlist thumbnailTrack];
284 masaki 281 NSTimeInterval ti = [playlist thumbnailTimeInterval];
285 masaki 269
286 masaki 281 [playlist removeThumbnailFrame];
287 masaki 269
288 masaki 281 if(prevThumbnailTrack) {
289 masaki 269 id undo = [self undoManager];
290 masaki 281 [[undo prepareWithInvocationTarget:playlist] setThumbnailComponent:prevThumbnailTrack timeIntarval:ti];
291     [undo setActionName:NSLocalizedString(@"Remove Thumbnail frame.", @"Undo Action Name Remove Thumbnail frame")];
292 masaki 269 }
293     }
294     - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
295     {
296     SEL action = [menuItem action];
297    
298 masaki 281 if(action == @selector(removeThumbnail:)) {
299 masaki 306 HMXSPFComponent *component = [playlist thumbnailTrack];
300 masaki 269 if(!component) return NO;
301     }
302    
303     return YES;
304     }
305 masaki 2
306 masaki 306 - (void)setPlaylist:(HMXSPFComponent *)newList
307 masaki 2 {
308 masaki 116 if(playlist == newList) return;
309 masaki 2
310 masaki 244 [[playlist childAtIndex:0] removeObserver:self forKeyPath:XspfQTCurrentTrackKey];
311 masaki 116 [playlist autorelease];
312     playlist = [newList retain];
313 masaki 171 [[playlist childAtIndex:0] addObserver:self
314 masaki 244 forKeyPath:XspfQTCurrentTrackKey
315 masaki 171 options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
316     context:NULL];
317 masaki 2 }
318 masaki 306 - (HMXSPFComponent *)playlist
319 masaki 116 {
320     return playlist;
321     }
322    
323 masaki 306 - (HMXSPFComponent *)trackList
324 masaki 2 {
325 masaki 116 return [playlist childAtIndex:0];
326 masaki 2 }
327    
328 masaki 196 + (NSSet *)keyPathsForValuesAffectingPlayingMovieDuration
329     {
330     return [NSSet setWithObject:@"playingMovie"];
331     }
332 masaki 171 - (void)setPlayingMovie:(QTMovie *)newMovie
333     {
334     NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
335 masaki 193 if(playingMovie) {
336 masaki 188 [nc removeObserver:self
337     name:nil
338     object:playingMovie];
339     }
340 masaki 171
341     [playingMovie autorelease];
342 masaki 181 playingMovie = [newMovie retain];
343 masaki 196 playingMovieDuration = 0;
344 masaki 171
345 masaki 193 if(playingMovie) {
346 masaki 188 [nc addObserver:self
347     selector:@selector(notifee:)
348     name:QTMovieRateDidChangeNotification
349     object:playingMovie];
350     }
351 masaki 171 }
352     - (QTMovie *)playingMovie
353     {
354     return playingMovie;
355     }
356 masaki 182 - (NSTimeInterval)playingMovieDuration
357     {
358     if(playingMovieDuration == 0) {
359     QTTime qttime = [[self playingMovie] duration];
360     if(!QTGetTimeInterval(qttime, &playingMovieDuration)) playingMovieDuration = 0;
361     }
362    
363     return playingMovieDuration;
364     }
365 masaki 171 - (void)loadMovie
366     {
367     NSURL *location = [[self trackList] movieLocation];
368    
369 masaki 174 if(playingMovie) {
370     id movieURL = [playingMovie attributeForKey:QTMovieURLAttribute];
371 masaki 181 if([location isEqualUsingLocalhost:movieURL]) return;
372 masaki 174 }
373    
374 masaki 182 [loader setMovieURL:location];
375 masaki 181 [loader load];
376     QTMovie *newMovie = [loader qtMovie];
377     [self setPlayingMovie:newMovie];
378 masaki 171
379     QTTime qttime = [newMovie duration];
380     id t = [NSValueTransformer valueTransformerForName:@"XspfQTTimeDateTransformer"];
381     [[self trackList] setCurrentTrackDuration:[t transformedValue:[NSValue valueWithQTTime:qttime]]];
382 masaki 182
383     didPreloading = NO;
384 masaki 171 }
385 masaki 242
386 masaki 171 - (void)observeValueForKeyPath:(NSString *)keyPath
387     ofObject:(id)object
388     change:(NSDictionary *)change
389     context:(void *)context
390     {
391 masaki 244 if([keyPath isEqualToString:XspfQTCurrentTrackKey]) {
392 masaki 242 [self loadMovie];
393 masaki 171 }
394     }
395 masaki 31
396 masaki 71 - (NSXMLDocument *)XMLDocument
397 masaki 31 {
398 masaki 116 id root = [[self playlist] XMLElement];
399 masaki 31
400     id d = [[[NSXMLDocument alloc] initWithRootElement:root] autorelease];
401     [d setVersion:@"1.0"];
402     [d setCharacterEncoding:@"UTF-8"];
403    
404     return d;
405     }
406 masaki 42
407 masaki 89 - (void)insertComponentFromURL:(NSURL *)url atIndex:(NSUInteger)index
408     {
409 masaki 306 id new = [HMXSPFComponent xspfTrackWithLocation:url];
410 masaki 89 if(!new) {
411     @throw self;
412     }
413    
414     [self insertComponent:new atIndex:index];
415     }
416 masaki 306 - (void)insertComponent:(HMXSPFComponent *)item atIndex:(NSUInteger)index
417 masaki 55 {
418 masaki 83 id undo = [self undoManager];
419 masaki 86 [undo registerUndoWithTarget:self selector:@selector(removeComponent:) object:item];
420 masaki 78 [[self trackList] insertChild:item atIndex:index];
421 masaki 261 [undo setActionName:NSLocalizedString(@"Insert Movie", @"Undo Action Name Insert Movie")];
422 masaki 55 }
423 masaki 306 - (void)removeComponent:(HMXSPFComponent *)item
424 masaki 55 {
425 masaki 83 NSUInteger index = [[self trackList] indexOfChild:item];
426 masaki 121 if(index == NSNotFound) {
427 masaki 269 NSLog(@"Can not found item (%@)", item);
428 masaki 121 return;
429     }
430 masaki 83
431     id undo = [self undoManager];
432 masaki 86 [[undo prepareWithInvocationTarget:self] insertComponent:item atIndex:index];
433 masaki 55 [[self trackList] removeChild:item];
434 masaki 261 [undo setActionName:NSLocalizedString(@"Remove Movie", @"Undo Action Name Remove Movie")];
435 masaki 55 }
436 masaki 247 - (void)moveComponentFromIndex:(NSUInteger)from toIndex:(NSUInteger)to
437     {
438     id undo = [self undoManager];
439     [[undo prepareWithInvocationTarget:self] moveComponentFromIndex:to toIndex:from];
440     [[self trackList] moveChildFromIndex:from toIndex:to];
441 masaki 261 [undo setActionName:NSLocalizedString(@"Move Movie", @"Undo Action Name Move Movie")];
442 masaki 247 }
443 masaki 306 - (void)moveComponent:(HMXSPFComponent *)item toIndex:(NSUInteger)index
444 masaki 247 {
445     NSUInteger from = [[self trackList] indexOfChild:item];
446     if(from == NSNotFound) return;
447     [self moveComponentFromIndex:from toIndex:index];
448     }
449 masaki 55
450 masaki 141 - (NSData *)dataFromURL:(NSURL *)url error:(NSError **)outError
451     {
452     NSURLRequest *req = [NSURLRequest requestWithURL:url];
453     NSURLResponse *res = nil;
454     NSError *err = nil;
455     NSData *data = [NSURLConnection sendSynchronousRequest:req
456     returningResponse:&res
457     error:&err];
458     if(err) {
459     if(outError) {
460     *outError = err;
461     }
462     return nil;
463     }
464    
465     return data;
466     }
467    
468 masaki 171 - (void)notifee:(id)notification
469     {
470     // NSLog(@"Notifed: name -> (%@)\ndict -> (%@)", [notification name], [notification userInfo]);
471    
472     id track = [[self trackList] currentTrack];
473     NSNumber *rateValue = [[notification userInfo] objectForKey:QTMovieRateDidChangeNotificationParameter];
474     if(rateValue) {
475     float rate = [rateValue floatValue];
476     if(rate == 0) {
477     [track setIsPlayed:NO];
478     } else {
479     [track setIsPlayed:YES];
480     }
481     }
482     }
483    
484 masaki 298 // call from XspfQTMovieTimer.
485 masaki 182 - (void)checkPreload:(NSTimer *)timer
486     {
487 masaki 205 if(![XspfQTPref preloadingEnabled]) return;
488 masaki 182 if(didPreloading) return;
489    
490     NSTimeInterval duration;
491     NSTimeInterval current;
492     QTTime qttime = [playingMovie currentTime];
493     if(!QTGetTimeInterval(qttime, &current)) return;
494    
495     duration = [self playingMovieDuration];
496    
497 masaki 205 if( current / duration > [XspfQTPref beginingPreloadPercent] ) {
498 masaki 182 didPreloading = YES;
499 masaki 306 HMXSPFComponent *list = [self trackList];
500 masaki 303 NSUInteger nextIndex = [list selectionIndex] + 1;
501     NSUInteger max = [list childrenCount];
502 masaki 182 if(max <= nextIndex) return;
503    
504 masaki 306 HMXSPFComponent *nextTrack = [list childAtIndex:nextIndex];
505 masaki 182 NSURL *nextMovieURL = [nextTrack movieLocation];
506     [loader setMovieURL:nextMovieURL];
507     [loader load];
508     }
509     }
510    
511 masaki 274 inline static BOOL isXspfFileType(NSString *typeName)
512     {
513     return [typeName isEqualToString:XspfDocumentType] || [typeName isEqualToString:XspfUTI];
514     }
515     inline static BOOL isReadableMovieType(NSString *typeName)
516     {
517     return [typeName isEqualToString:QuickTimeMovieDocumentType]
518     || [typeName isEqualToString:MatroskaVideoDocumentType]
519     || [typeName isEqualToString:DivXMediaFormatDocumentType];
520     }
521    
522 masaki 2 @end
523    

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