Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /XspfQT/XspfQTDocument.m

Parent Directory Parent Directory | Revision Log Revision Log


Revision 274 - (hide annotations) (download)
Fri Oct 23 19:10:38 2009 UTC (14 years, 5 months ago) by masaki
File size: 12896 byte(s)
[Refactoring] typeNameの識別を関数にまとめてコードを読みやすくした。
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     NSString *xmlElem;
115     xmlElem = [NSString stringWithFormat:@"<track><location>%@</location></track>",
116     [absoluteURL absoluteString]];
117    
118     NSError *error = nil;
119     id new = [XspfQTComponent xspfComponentWithXMLElementString:xmlElem
120     error:&error];
121     if(error) {
122     NSLog(@"%@", error);
123     if(outError) {
124     *outError = error;
125     }
126     return NO;
127     }
128    
129     id pl = [XspfQTComponent xspfPlaylist];
130     if(!pl) {
131     return NO;
132     }
133    
134     [[[pl children] objectAtIndex:0] addChild:new];
135    
136     [self setPlaylist:pl];
137     id t = [self trackList];
138     if(![t title]) {
139     [t setTitle:[[[self fileURL] path] lastPathComponent]];
140     }
141    
142 masaki 207 [self setFileType:XspfDocumentType];
143 masaki 141 [self setFileURL:nil];
144    
145     return YES;
146     }
147 masaki 2 - (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
148     {
149 masaki 274 if(!isXspfFileType(typeName)) {
150 masaki 141 return NO;
151     }
152    
153 masaki 2 NSError *error = nil;
154 masaki 10 NSXMLDocument *d = [[[NSXMLDocument alloc] initWithData:data
155     options:0
156     error:&error] autorelease];
157 masaki 121 if(error) {
158     NSLog(@"%@", error);
159 masaki 272 if(outError) {
160     *outError = error;
161     }
162 masaki 121 return NO;
163     }
164 masaki 2 NSXMLElement *root = [d rootElement];
165 masaki 116 id pl = [XspfQTComponent xspfComponemtWithXMLElement:root];
166 masaki 121 if(!pl) {
167     NSLog(@"Can not create XspfQTComponent.");
168     return NO;
169     }
170 masaki 116 [self setPlaylist:pl];
171 masaki 2
172 masaki 116 id t = [self trackList];
173 masaki 39 if(![t title]) {
174 masaki 165 [t setTitle:[[[[self fileURL] path] lastPathComponent] stringByDeletingPathExtension]];
175 masaki 39 }
176 masaki 272
177 masaki 2 return YES;
178     }
179    
180 masaki 42 - (void)close
181     {
182 masaki 61 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
183 masaki 72 [nc postNotificationName:XspfQTDocumentWillCloseNotification object:self];
184 masaki 61
185 masaki 42 [self removeWindowController:playListWindowController];
186     [playListWindowController release];
187     playListWindowController = nil;
188    
189     [self removeWindowController:movieWindowController];
190     [movieWindowController release];
191     movieWindowController = nil;
192    
193 masaki 189 [preloadingTimer invalidate];
194    
195 masaki 42 [super close];
196     }
197    
198 masaki 269 #pragma mark### Actions ###
199 masaki 33 - (IBAction)togglePlayAndPause:(id)sender
200     {
201     [movieWindowController togglePlayAndPause:sender];
202     }
203 masaki 2 - (IBAction)showPlayList:(id)sender
204     {
205     [playListWindowController showWindow:self];
206     }
207 masaki 269 - (IBAction)setThumnailFrame:(id)sender
208     {
209     XspfQTComponent *currentTrack = [[self trackList] currentTrack];
210     QTTime currentQTTime = [playingMovie currentTime];
211    
212     NSTimeInterval currentTI;
213     QTGetTimeInterval(currentQTTime, &currentTI);
214    
215     XspfQTComponent *prevThumnailTrack = [playlist thumnailTrack];
216     NSTimeInterval ti = [playlist thumnailTimeIntarval];
217    
218     [playlist setThumnailComponent:currentTrack timeIntarval:currentTI];
219    
220     id undo = [self undoManager];
221     if(prevThumnailTrack) {
222     [[undo prepareWithInvocationTarget:playlist] setThumnailComponent:prevThumnailTrack timeIntarval:ti];
223     [undo setActionName:NSLocalizedString(@"Change Thumnail frame.", @"Undo Action Name Change Thumnail frame")];
224     } else {
225     [[undo prepareWithInvocationTarget:playlist] removeThumnailFrame];
226     [undo setActionName:NSLocalizedString(@"Add Thumnail frame.", @"Undo Action Name Add Thumnail frame")];
227     }
228     }
229     - (IBAction)removeThumail:(id)sender
230     {
231     XspfQTComponent *prevThumnailTrack = [playlist thumnailTrack];
232     NSTimeInterval ti = [playlist thumnailTimeIntarval];
233    
234     [playlist removeThumnailFrame];
235    
236     if(prevThumnailTrack) {
237     id undo = [self undoManager];
238     [[undo prepareWithInvocationTarget:playlist] setThumnailComponent:prevThumnailTrack timeIntarval:ti];
239     [undo setActionName:NSLocalizedString(@"Remove Thumnail frame.", @"Undo Action Name Remove Thumnail frame")];
240     }
241     }
242     - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
243     {
244     SEL action = [menuItem action];
245    
246     if(action == @selector(removeThumail:)) {
247     XspfQTComponent *component = [playlist thumnailTrack];
248     if(!component) return NO;
249     }
250    
251     return YES;
252     }
253 masaki 2
254 masaki 116 - (void)setPlaylist:(XspfQTComponent *)newList
255 masaki 2 {
256 masaki 116 if(playlist == newList) return;
257 masaki 2
258 masaki 244 [[playlist childAtIndex:0] removeObserver:self forKeyPath:XspfQTCurrentTrackKey];
259 masaki 116 [playlist autorelease];
260     playlist = [newList retain];
261 masaki 171 [[playlist childAtIndex:0] addObserver:self
262 masaki 244 forKeyPath:XspfQTCurrentTrackKey
263 masaki 171 options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
264     context:NULL];
265 masaki 2 }
266 masaki 116 - (XspfQTComponent *)playlist
267     {
268     return playlist;
269     }
270    
271 masaki 72 - (XspfQTComponent *)trackList
272 masaki 2 {
273 masaki 116 return [playlist childAtIndex:0];
274 masaki 2 }
275    
276 masaki 196 + (NSSet *)keyPathsForValuesAffectingPlayingMovieDuration
277     {
278     return [NSSet setWithObject:@"playingMovie"];
279     }
280 masaki 171 - (void)setPlayingMovie:(QTMovie *)newMovie
281     {
282     NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
283 masaki 193 if(playingMovie) {
284 masaki 188 [nc removeObserver:self
285     name:nil
286     object:playingMovie];
287     }
288 masaki 171
289     [playingMovie autorelease];
290 masaki 181 playingMovie = [newMovie retain];
291 masaki 196 playingMovieDuration = 0;
292 masaki 171
293 masaki 193 if(playingMovie) {
294 masaki 188 [nc addObserver:self
295     selector:@selector(notifee:)
296     name:QTMovieRateDidChangeNotification
297     object:playingMovie];
298     }
299 masaki 171 }
300     - (QTMovie *)playingMovie
301     {
302     return playingMovie;
303     }
304 masaki 182 - (NSTimeInterval)playingMovieDuration
305     {
306     if(playingMovieDuration == 0) {
307     QTTime qttime = [[self playingMovie] duration];
308     if(!QTGetTimeInterval(qttime, &playingMovieDuration)) playingMovieDuration = 0;
309     }
310    
311     return playingMovieDuration;
312     }
313 masaki 171 - (void)loadMovie
314     {
315     NSURL *location = [[self trackList] movieLocation];
316    
317 masaki 174 if(playingMovie) {
318     id movieURL = [playingMovie attributeForKey:QTMovieURLAttribute];
319 masaki 181 if([location isEqualUsingLocalhost:movieURL]) return;
320 masaki 174 }
321    
322 masaki 182 [loader setMovieURL:location];
323 masaki 181 [loader load];
324     QTMovie *newMovie = [loader qtMovie];
325     [self setPlayingMovie:newMovie];
326 masaki 171
327     QTTime qttime = [newMovie duration];
328     id t = [NSValueTransformer valueTransformerForName:@"XspfQTTimeDateTransformer"];
329     [[self trackList] setCurrentTrackDuration:[t transformedValue:[NSValue valueWithQTTime:qttime]]];
330 masaki 182
331     didPreloading = NO;
332 masaki 171 }
333 masaki 242
334 masaki 171 - (void)observeValueForKeyPath:(NSString *)keyPath
335     ofObject:(id)object
336     change:(NSDictionary *)change
337     context:(void *)context
338     {
339 masaki 244 if([keyPath isEqualToString:XspfQTCurrentTrackKey]) {
340 masaki 242 [self loadMovie];
341 masaki 171 }
342     }
343 masaki 31
344 masaki 71 - (NSXMLDocument *)XMLDocument
345 masaki 31 {
346 masaki 116 id root = [[self playlist] XMLElement];
347 masaki 31
348     id d = [[[NSXMLDocument alloc] initWithRootElement:root] autorelease];
349     [d setVersion:@"1.0"];
350     [d setCharacterEncoding:@"UTF-8"];
351    
352     return d;
353     }
354 masaki 42
355 masaki 89 - (void)insertComponentFromURL:(NSURL *)url atIndex:(NSUInteger)index
356     {
357     NSString *xmlElem;
358     xmlElem = [NSString stringWithFormat:@"<track><location>%@</location></track>",
359     [url absoluteString]];
360    
361     NSError *error = nil;
362 masaki 117 id new = [XspfQTComponent xspfComponentWithXMLElementString:xmlElem
363     error:&error];
364 masaki 89 if(error) {
365     NSLog(@"%@", error);
366     @throw self;
367     }
368    
369     if(!new) {
370     @throw self;
371     }
372    
373     [self insertComponent:new atIndex:index];
374     }
375 masaki 86 - (void)insertComponent:(XspfQTComponent *)item atIndex:(NSUInteger)index
376 masaki 55 {
377 masaki 83 id undo = [self undoManager];
378 masaki 86 [undo registerUndoWithTarget:self selector:@selector(removeComponent:) object:item];
379 masaki 78 [[self trackList] insertChild:item atIndex:index];
380 masaki 261 [undo setActionName:NSLocalizedString(@"Insert Movie", @"Undo Action Name Insert Movie")];
381 masaki 55 }
382 masaki 86 - (void)removeComponent:(XspfQTComponent *)item
383 masaki 55 {
384 masaki 83 NSUInteger index = [[self trackList] indexOfChild:item];
385 masaki 121 if(index == NSNotFound) {
386 masaki 269 NSLog(@"Can not found item (%@)", item);
387 masaki 121 return;
388     }
389 masaki 83
390     id undo = [self undoManager];
391 masaki 86 [[undo prepareWithInvocationTarget:self] insertComponent:item atIndex:index];
392 masaki 55 [[self trackList] removeChild:item];
393 masaki 261 [undo setActionName:NSLocalizedString(@"Remove Movie", @"Undo Action Name Remove Movie")];
394 masaki 55 }
395 masaki 247 - (void)moveComponentFromIndex:(NSUInteger)from toIndex:(NSUInteger)to
396     {
397     id undo = [self undoManager];
398     [[undo prepareWithInvocationTarget:self] moveComponentFromIndex:to toIndex:from];
399     [[self trackList] moveChildFromIndex:from toIndex:to];
400 masaki 261 [undo setActionName:NSLocalizedString(@"Move Movie", @"Undo Action Name Move Movie")];
401 masaki 247 }
402     - (void)moveComponent:(XspfQTComponent *)item toIndex:(NSUInteger)index
403     {
404     NSUInteger from = [[self trackList] indexOfChild:item];
405     if(from == NSNotFound) return;
406     [self moveComponentFromIndex:from toIndex:index];
407     }
408 masaki 55
409 masaki 141 - (NSData *)dataFromURL:(NSURL *)url error:(NSError **)outError
410     {
411     NSURLRequest *req = [NSURLRequest requestWithURL:url];
412     NSURLResponse *res = nil;
413     NSError *err = nil;
414     NSData *data = [NSURLConnection sendSynchronousRequest:req
415     returningResponse:&res
416     error:&err];
417     if(err) {
418     if(outError) {
419     *outError = err;
420     }
421     return nil;
422     }
423    
424     return data;
425     }
426    
427 masaki 171 - (void)notifee:(id)notification
428     {
429     // NSLog(@"Notifed: name -> (%@)\ndict -> (%@)", [notification name], [notification userInfo]);
430    
431     id track = [[self trackList] currentTrack];
432     NSNumber *rateValue = [[notification userInfo] objectForKey:QTMovieRateDidChangeNotificationParameter];
433     if(rateValue) {
434     float rate = [rateValue floatValue];
435     if(rate == 0) {
436     [track setIsPlayed:NO];
437     } else {
438     [track setIsPlayed:YES];
439     }
440     }
441     }
442    
443 masaki 182 - (void)checkPreload:(NSTimer *)timer
444     {
445 masaki 205 if(![XspfQTPref preloadingEnabled]) return;
446 masaki 182 if(didPreloading) return;
447    
448     NSTimeInterval duration;
449     NSTimeInterval current;
450     QTTime qttime = [playingMovie currentTime];
451     if(!QTGetTimeInterval(qttime, &current)) return;
452    
453     duration = [self playingMovieDuration];
454    
455 masaki 205 if( current / duration > [XspfQTPref beginingPreloadPercent] ) {
456 masaki 182 didPreloading = YES;
457     XspfQTComponent *list = [self trackList];
458     unsigned nextIndex = [list selectionIndex] + 1;
459     unsigned max = [list childrenCount];
460     if(max <= nextIndex) return;
461    
462     XspfQTComponent *nextTrack = [list childAtIndex:nextIndex];
463     NSURL *nextMovieURL = [nextTrack movieLocation];
464     [loader setMovieURL:nextMovieURL];
465     [loader load];
466     }
467     }
468    
469 masaki 274 inline static BOOL isXspfFileType(NSString *typeName)
470     {
471     return [typeName isEqualToString:XspfDocumentType] || [typeName isEqualToString:XspfUTI];
472     }
473     inline static BOOL isReadableMovieType(NSString *typeName)
474     {
475     return [typeName isEqualToString:QuickTimeMovieDocumentType]
476     || [typeName isEqualToString:MatroskaVideoDocumentType]
477     || [typeName isEqualToString:DivXMediaFormatDocumentType];
478     }
479    
480 masaki 2 @end
481    

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