Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /XspfQT/XspfQTDocument.m

Parent Directory Parent Directory | Revision Log Revision Log


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

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