-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAppController.m
839 lines (748 loc) · 31 KB
/
AppController.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
//
// Movist
//
// Copyright 2006 ~ 2008 Yong-Hoe Kim. All rights reserved.
// Yong-Hoe Kim <[email protected]>
//
// This file is part of Movist.
//
// Movist is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3 of the License, or
// (at your option) any later version.
//
// Movist is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#import "AppController.h"
#import "UpdateChecker.h"
#import "UserDefaults.h"
#import "MMovie_FFmpeg.h"
#import "MMovie_QuickTime.h"
#import "Playlist.h"
#import "PlaylistController.h"
#import "PreferenceController.h"
#import "MMovieView.h"
#import "MainWindow.h"
#import "FullScreener.h"
#import "FullWindow.h"
#import "PlayPanel.h"
#import "CustomControls.h"
#import "ControlPanel.h"
@implementation AppController
NSString* videoCodecName(int codecId);
+ (void)initialize
{
detectOperatingSystem();
av_register_all();
[[NSUserDefaults standardUserDefaults] registerMovistDefaults];
}
- (id)init
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
if (self = [super init]) {
_playlist = [[Playlist alloc] init];
_audioTrackIndexSet = [[NSMutableIndexSet alloc] init];
_subtitleNameSet = [[NSMutableSet alloc] init];
_fullScreenLock = [[NSLock alloc] init];
_defaults = [NSUserDefaults standardUserDefaults];
[MMovie_QuickTime checkA52CodecInstalled];
[MMovie_QuickTime checkPerianInstalled];
}
return self;
}
- (void)awakeFromNib
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
[self initDigitalAudioOut];
[self initRemoteControl];
// init UI
[_mainWindow setReleasedWhenClosed:FALSE];
[_mainWindow setExcludedFromWindowsMenu:TRUE];
[_playPanel setControlPanel:_controlPanel];
[self updatePlayUI];
[_volumeSlider setMinValue:MIN_VOLUME];
[_volumeSlider setMaxValue:MAX_VOLUME];
[_volumeSlider replaceCell:[CustomSliderCell class]];
CustomSliderCell* cell = [_volumeSlider cell];
[cell setImageName:@"MainVolume" backColor:nil trackOffset:5.0 knobOffset:2.0];
[_fsVolumeSlider setMinValue:MIN_VOLUME];
[_fsVolumeSlider setMaxValue:MAX_VOLUME];
[_fsVolumeSlider replaceCell:[CustomSliderCell class]];
cell = [_fsVolumeSlider cell];
[cell setImageName:@"FSVolume" backColor:HUDBackgroundColor trackOffset:0.0 knobOffset:2.0];
_alwaysOnTopEnabled = FALSE;
_checkForAltVolumeChange = TRUE;
_systemVolume = [self systemVolume];
[self updateVolumeUI];
_playRate = DEFAULT_PLAY_RATE;
_prevMovieTime = 0.0;
_lastPlayedMovieURL = nil;
_lastPlayedMovieTime = 0.0;
_lastPlayedMovieRepeatRange.length = 0.0;
_viewDuration = [_defaults boolForKey:MViewDurationKey];
[_lTimeTextField setClickable:FALSE]; [_fsLTimeTextField setClickable:FALSE];
[_rTimeTextField setClickable:TRUE]; [_fsRTimeTextField setClickable:TRUE];
_decoderButton = [_mainWindow createDecoderButton];
[_subtitleLanguageSegmentedControl setSelectedSegment:1]; // "subtitle 1"
[self updateDecoderUI];
[self updateDataSizeBpsUI];
initSubtitleEncodingMenu(_subtitle0EncodingMenu, @selector(reopenSubtitleAction:));
initSubtitleEncodingMenu(_subtitle1EncodingMenu, @selector(reopenSubtitleAction:));
initSubtitleEncodingMenu(_subtitle2EncodingMenu, @selector(reopenSubtitleAction:));
NSNotificationCenter* nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:@selector(subtitleTrackWillLoad:)
name:MSubtitleTrackWillLoadNotification object:nil];
[nc addObserver:self selector:@selector(subtitleTrackIsLoading:)
name:MSubtitleTrackIsLoadingNotification object:nil];
[nc addObserver:self selector:@selector(subtitleTrackDidLoad:)
name:MSubtitleTrackDidLoadNotification object:nil];
// modify menu-item shortcuts with shift modifier.
NSMenuItem* item;
NSEnumerator* e = [[_controlMenu itemArray] objectEnumerator];
while (item = [e nextObject]) {
if ([item action] == @selector(rateAction:) && [item tag] == 0) {
[item setKeyEquivalent:@"\\"];
[item setKeyEquivalentModifierMask:NSCommandKeyMask | NSShiftKeyMask];
break;
}
}
e = [[_subtitleMenu itemArray] objectEnumerator];
while (item = [e nextObject]) {
if ([item action] == @selector(subtitleSyncAction:) && [item tag] == 0) {
[item setKeyEquivalent:@"="];
[item setKeyEquivalentModifierMask:NSControlKeyMask | NSShiftKeyMask];
break;
}
}
}
- (void)dealloc
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
[self cleanupRemoteControl];
[self closeMovie];
[_decoderButton release];
[_fullScreenLock release];
[_subtitleNameSet release];
[_audioTrackIndexSet release];
[_lastPlayedMovieURL release];
[_playlist release];
[_playlistController release];
[_preferenceController release];
[[NSNotificationCenter defaultCenter] removeObserver:self];
[super dealloc];
}
////////////////////////////////////////////////////////////////////////////////
#pragma mark -
- (void)checkLegacyPreferences
{
// @"AutoFullScreen" is replaced with MOpeningViewKey.
id value = [_defaults objectForKey:@"AutoFullScreen"];
if (value) {
[_defaults removeObjectForKey:@"AutoFullScreen"];
if ([value boolValue] != FALSE) { // default was FALSE
[_defaults setInteger:OPENING_VIEW_FULL_SCREEN forKey:MOpeningViewKey];
}
}
// @"BlackoutSecondaryScreen" is renamed to MFullScreenBlackScreensKey.
value = [_defaults objectForKey:@"BlackoutSecondaryScreen"];
if (value) {
[_defaults removeObjectForKey:@"BlackoutSecondaryScreen"];
if ([value boolValue] != FALSE) { // default was FALSE
[_defaults setBool:TRUE forKey:MFullScreenBlackScreensKey];
}
}
// @"SubtitlePosition" is changed to MLetterBoxHeightKey and MSubtitleVPositionKey[0].
value = [_defaults objectForKey:@"SubtitlePosition"];
if (value) {
[_defaults removeObjectForKey:@"SubtitlePosition"];
if ([value intValue] != 100) { // default was 100 ("auto")
switch ([value intValue]) {
case -1 : // -1 is "on movie"
[_defaults setInteger:OSD_VPOSITION_BOTTOM forKey:MSubtitleVPositionKey[0]];
[_defaults setInteger:LETTER_BOX_HEIGHT_SAME forKey:MLetterBoxHeightKey];
break;
case 0 : // 0 is "on letter-box"
[_defaults setInteger:OSD_VPOSITION_LBOX forKey:MSubtitleVPositionKey[0]];
[_defaults setInteger:LETTER_BOX_HEIGHT_SAME forKey:MLetterBoxHeightKey];
break;
case 1 : // 1 is "on letter-box (1 line)"
[_defaults setInteger:OSD_VPOSITION_LBOX forKey:MSubtitleVPositionKey[0]];
[_defaults setInteger:LETTER_BOX_HEIGHT_1_LINE forKey:MLetterBoxHeightKey];
break;
case 2 : // 2 is "on letter-box (2 lines)"
[_defaults setInteger:OSD_VPOSITION_LBOX forKey:MSubtitleVPositionKey[0]];
[_defaults setInteger:LETTER_BOX_HEIGHT_2_LINES forKey:MLetterBoxHeightKey];
break;
case 3 : // 3 is "on letter-box (3 lines)"
[_defaults setInteger:OSD_VPOSITION_LBOX forKey:MSubtitleVPositionKey[0]];
[_defaults setInteger:LETTER_BOX_HEIGHT_3_LINES forKey:MLetterBoxHeightKey];
break;
}
}
}
// @"OpeningResize" is changed to MOpeningViewKey and MMovieResizeCenterKey.
value = [_defaults objectForKey:@"OpeningResize"];
if (value) {
[_defaults removeObjectForKey:@"OpeningResize"];
switch ([value intValue]) {
case 0 : // 0 is "never resize"
[_defaults setInteger:OPENING_VIEW_NONE forKey:MOpeningViewKey];
break;
case 1 : // 1 is "title center"
[_defaults setInteger:MOVIE_RESIZE_CENTER_TM forKey:MMovieResizeCenterKey];
break;
case 2 : // 2 is "bottom center"
[_defaults setInteger:MOVIE_RESIZE_CENTER_BM forKey:MMovieResizeCenterKey];
break;
case 3 : // 3 is "bottom right"
[_defaults setInteger:MOVIE_RESIZE_CENTER_BR forKey:MMovieResizeCenterKey];
break;
}
}
// @"WindowResize" is renamed to MWindowResizeModeKey.
value = [_defaults objectForKey:@"WindowResize"];
if (value) {
[_defaults removeObjectForKey:@"WindowResize"];
if ([value intValue] != 1) { // default was "adjust to size"
[_defaults setInteger:[value intValue] forKey:MWindowResizeModeKey];
}
}
// @"DraggingAction" is renamed to MViewDragActionKey.
value = [_defaults objectForKey:@"DraggingAction"];
if (value) {
[_defaults removeObjectForKey:@"DraggingAction"];
if ([value intValue] != 0) { // default was 0 ("none")
[_defaults setInteger:[value intValue] forKey:MViewDragActionKey];
}
}
// @"DisablePerianSubtitle" is renamed to MUseQuickTimeSubtitlesKey.
value = [_defaults objectForKey:@"DisablePerianSubtitle"];
if (value) {
[_defaults removeObjectForKey:@"DisablePerianSubtitle"];
if ([value boolValue] != TRUE) { // default was TRUE.
[_defaults setInteger:![value boolValue] forKey:MUseQuickTimeSubtitlesKey];
}
}
// @"AutoSubtitlePositionMaxLines" is renamed to MAutoLetterBoxHeightMaxLinesKey.
value = [_defaults objectForKey:@"AutoSubtitlePositionMaxLines"];
if (value) {
[_defaults removeObjectForKey:@"AutoSubtitlePositionMaxLines"];
if ([value intValue] != 2) { // default was 2.
[_defaults setInteger:[value intValue] forKey:MAutoLetterBoxHeightMaxLinesKey];
}
}
}
- (void)applicationWillFinishLaunching:(NSNotification*)aNotification
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
// hover-images should be set after -awakeFromNib.
[_prevSeekButton setHoverImage:[NSImage imageNamed:@"MainPrevSeekHover"]];
[_nextSeekButton setHoverImage:[NSImage imageNamed:@"MainNextSeekHover"]];
[_controlPanelButton setHoverImage:[NSImage imageNamed:@"MainControlPanelHover"]];
[_prevMovieButton setHoverImage:[NSImage imageNamed:@"MainPrevMovieHover"]];
[_nextMovieButton setHoverImage:[NSImage imageNamed:@"MainNextMovieHover"]];
[_playlistButton setHoverImage:[NSImage imageNamed:@"MainPlaylistHover"]];
[self checkLegacyPreferences];
// initial update preferences: general
[self setAlwaysOnTopEnabled:[_defaults boolForKey:MAlwaysOnTopKey]];
// don't set as-desktop-background. it will be set when movie is opened.
[self setSeekInterval:[_defaults floatForKey:MSeekInterval0Key] atIndex:0];
[self setSeekInterval:[_defaults floatForKey:MSeekInterval1Key] atIndex:1];
[self setSeekInterval:[_defaults floatForKey:MSeekInterval2Key] atIndex:2];
// initial update preferences: video
[_movieView setFullScreenUnderScan:[_defaults floatForKey:MFullScreenUnderScanKey]];
// initial update preferences: audio
// ...
// initial update preferences: subtitle
// check if subtitle font exist. if not, then restore to default.
SubtitleAttributes attrs;
attrs.mask = SUBTITLE_ATTRIBUTE_FONT | SUBTITLE_ATTRIBUTE_TEXT_COLOR |
SUBTITLE_ATTRIBUTE_STROKE_COLOR | SUBTITLE_ATTRIBUTE_STROKE_WIDTH |
SUBTITLE_ATTRIBUTE_SHADOW_COLOR | SUBTITLE_ATTRIBUTE_SHADOW_BLUR |
SUBTITLE_ATTRIBUTE_SHADOW_OFFSET | SUBTITLE_ATTRIBUTE_SHADOW_DARKNESS |
SUBTITLE_ATTRIBUTE_LINE_SPACING | SUBTITLE_ATTRIBUTE_V_POSITION |
SUBTITLE_ATTRIBUTE_H_MARGIN | SUBTITLE_ATTRIBUTE_V_MARGIN;
int i;
NSFont* font;
NSString* fontName;
for (i = 0; i < 3; i++) {
fontName = [_defaults stringForKey:MSubtitleFontNameKey[i]];
font = [NSFont fontWithName:fontName size:10.0];
if (!font) {
runAlertPanel(_mainWindow,
NSLocalizedString(@"Subtitle Font Not Found", nil),
[NSString stringWithFormat:NSLocalizedString(
@"\"%@\" not found\n"
"Subtitle font setting will be restored to default.", nil),
fontName],
NSLocalizedString(@"OK", nil), nil, nil);
[_defaults setObject:[[NSFont boldSystemFontOfSize:1.0] fontName]
forKey:MSubtitleFontNameKey[i]];
}
attrs.fontName = [_defaults stringForKey:MSubtitleFontNameKey[i]];
attrs.fontSize = [_defaults floatForKey:MSubtitleFontSizeKey[i]];
attrs.textColor = [_defaults colorForKey:MSubtitleTextColorKey[i]];
attrs.strokeColor = [_defaults colorForKey:MSubtitleStrokeColorKey[i]];
attrs.strokeWidth = [_defaults floatForKey:MSubtitleStrokeWidthKey[i]];
attrs.shadowColor = [_defaults colorForKey:MSubtitleShadowColorKey[i]];
attrs.shadowBlur = [_defaults floatForKey:MSubtitleShadowBlurKey[i]];
attrs.shadowOffset = [_defaults floatForKey:MSubtitleShadowOffsetKey[i]];
attrs.shadowDarkness= [_defaults integerForKey:MSubtitleShadowDarknessKey[i]];
attrs.vPosition = [_defaults integerForKey:MSubtitleVPositionKey[i]];
attrs.hMargin = [_defaults floatForKey:MSubtitleHMarginKey[i]];
attrs.vMargin = [_defaults floatForKey:MSubtitleVMarginKey[i]];
attrs.lineSpacing = [_defaults floatForKey:MSubtitleLineSpacingKey[i]];
[_movieView setSubtitleAttributes:&attrs atIndex:i];
}
[_movieView setLetterBoxHeight:[_defaults integerForKey:MLetterBoxHeightKey]];
[_movieView setSubtitleScreenMargin:[_defaults floatForKey:MSubtitleScreenMarginKey]];
// initial update preferences: advanced
// ...
// initial update preferences: advanced - details : general
[_movieView setActivateOnDragging:[_defaults boolForKey:MActivateOnDraggingKey]];
[_movieView setViewDragAction:[_defaults integerForKey:MViewDragActionKey]];
// initial update preferences: advanced - details : video
[_movieView setCaptureFormat:[_defaults integerForKey:MCaptureFormatKey]];
[self setIncludeLetterBoxOnCapture:[_defaults boolForKey:MIncludeLetterBoxOnCaptureKey]];
[_movieView setRemoveGreenBox:[_defaults boolForKey:MRemoveGreenBoxKey]];
// initial update preferences: advanced - details : subtitle
[MMovie_QuickTime setUseQuickTimeSubtitles:[_defaults boolForKey:MUseQuickTimeSubtitlesKey]];
[_movieView setAutoLetterBoxHeightMaxLines:[_defaults integerForKey:MAutoLetterBoxHeightMaxLinesKey]];
// initial update preferences: advanced - details : full-nav
// ...
[self updateUI];
[self checkForUpdatesOnStartup];
[self loadLastPlayedMovieInfo];
}
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification
{
if ([_defaults boolForKey:MFullNavUseKey] &&
[_defaults boolForKey:MFullNavOnStartupKey]) {
[self beginFullNavigation];
}
else if (!_movie && _lastPlayedMovieURL) {
// open last played movie (but, no play)
float rate = _playRate;
_playRate = 0.0; // no play
[self openCurrentPlaylistItem];
_playRate = rate;
}
}
- (void)applicationWillBecomeActive:(NSNotification*)aNotification
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
if ([_defaults boolForKey:MSupportAppleRemoteKey]) {
[self startRemoteControl];
}
}
- (void)applicationWillResignActive:(NSNotification*)aNotification
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
if ([_playPanel isVisible]) {
[_playPanel orderOut:self];
}
if ([_defaults boolForKey:MSupportAppleRemoteKey]) {
[self stopRemoteControl];
}
}
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)theApplication
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
return [_defaults boolForKey:MQuitWhenWindowCloseKey];
}
- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApplication
hasVisibleWindows:(BOOL)flag
{
//TRACE(@"%s %d", __PRETTY_FUNCTION__, flag);
[_mainWindow makeKeyAndOrderFront:self];
return FALSE;
}
- (void)applicationWillTerminate:(NSNotification*)aNotification
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
[self closeMovie];
[self saveLastPlayedMovieInfo];
[_defaults synchronize];
}
- (void)checkProcessArguments
{
/*
NSArray* arguments = [[NSProcessInfo processInfo] arguments];
NSArray* options = [NSArray arrayWithObjects:@"--decoder=", nil];
"--fullNavMode"
NSString* arg, *opt;
NSEnumerator* optEnumerator;
NSEnumerator* argEnumerator = [arguments objectEnumerator];
while (arg = [enumerator nextObject]) {
optEnumerator = [options objectEnumerator];
while (opt = [optEnumerator nextObject]) {
if (NSOrderedSame == [arg compare:opt options:0 range:NSMakeRange(0, [opt length])]) {
}
}
}
runAlertPanel(_mainWindow, title, @"", NSLocalizedString(@"OK", nil), nil, nil);
*/
}
- (BOOL)application:(NSApplication*)theApplication openFile:(NSString*)filename
{
//TRACE(@"%s:\"%@\"", __PRETTY_FUNCTION__, filename);
[self checkProcessArguments];
if ([self isFullNavigation] && [_fullScreener isNavigating]) {
return FALSE;
}
return [self openFile:filename];
}
- (void)application:(NSApplication*)theApplication openFiles:(NSArray*)filenames
{
//TRACE(@"%s:{%@}", __PRETTY_FUNCTION__, filenames);
[self checkProcessArguments];
if ([self isFullNavigation] && [_fullScreener isNavigating]) {
return;
}
if ([self openFiles:filenames]) {
[NSApp replyToOpenOrPrint:NSApplicationDelegateReplySuccess];
}
else {
[NSApp replyToOpenOrPrint:NSApplicationDelegateReplyFailure];
}
}
- (void)windowWillClose:(NSNotification*)aNotification
{
if ([aNotification object] != [_movieView window]) {
[[_movieView window] makeKeyWindow];
}
}
////////////////////////////////////////////////////////////////////////////////
#pragma mark -
- (MMovie*)movie { return _movie; }
- (NSURL*)movieURL { return (_movie) ? [[_playlist currentItem] movieURL] : nil; }
- (void)updateUI
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
NSURL* movieURL = [self movieURL];
[_mainWindow setMovieURL:movieURL];
[_fullScreener setMovieURL:movieURL];
[_controlPanel setMovieURL:movieURL];
[_propertiesView reloadData];
[_seekSlider setDuration:(_movie) ? [_movie duration] : 0];
[_fsSeekSlider setDuration:[_seekSlider duration]];
[self updatePrevNextMovieButtons];
[self updateAspectRatioMenu];
[self updateFullScreenFillMenu];
[self updateAudioTrackMenuItems];
[self updateVolumeMenuItems];
[self updateSubtitleLanguageMenuItems];
[self updateSubtitlePositionMenuItems:0];
[self updateSubtitlePositionMenuItems:1];
[self updateSubtitlePositionMenuItems:2];
[self updateLetterBoxHeightMenuItems];
[self updateRepeatUI];
[self updateVolumeUI];
[self updateTimeUI];
[self updatePlayUI];
[self updateDecoderUI];
[self updateDataSizeBpsUI];
[_playlistController updateUI];
}
- (void)setIncludeLetterBoxOnCapture:(BOOL)includeLetterBox
{
[_movieView setIncludeLetterBoxOnCapture:includeLetterBox];
[_altCopyImageMenuItem setTitle:(includeLetterBox) ?
NSLocalizedString(@"Copy (Excluding Letter Box)", nil) :
NSLocalizedString(@"Copy (Including Letter Box)", nil)];
[_altSaveImageMenuItem setTitle:(includeLetterBox) ?
NSLocalizedString(@"Save Current Image (Excluding Letter Box)", nil) :
NSLocalizedString(@"Save Current Image (Including Letter Box)", nil)];
}
////////////////////////////////////////////////////////////////////////////////
#pragma mark -
- (void)checkForUpdatesOnStartup
{
NSTimeInterval timeInterval;
switch ([_defaults integerForKey:MUpdateCheckIntervalKey]) {
case CHECK_UPDATE_NEVER : return; // don't check automatically
case CHECK_UPDATE_DAILY : timeInterval = 1 * 24 * 60 * 60; break;
case CHECK_UPDATE_WEEKLY : timeInterval = 7 * 24 * 60 * 60; break;
case CHECK_UPDATE_MONTHLY :
default : timeInterval = 30 * 24 * 60 * 60; break;
}
NSDate* lastCheckTime = [_defaults objectForKey:MLastUpdateCheckTimeKey];
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:lastCheckTime];
if (timeInterval <= interval) {
[self checkForUpdates:FALSE];
}
}
- (void)checkForUpdates:(BOOL)manual
{
[_movieView setMessage:NSLocalizedString(@"Checking for Updates...", nil)];
[_movieView display];
NSError* error;
UpdateChecker* checker = [[UpdateChecker alloc] init];
int ret = [checker checkUpdate:&error];
[_defaults setObject:[NSDate date] forKey:MLastUpdateCheckTimeKey];
[_preferenceController updateLastUpdateCheckTimeTextField];
if (ret == UPDATE_CHECK_FAILED) {
if (manual) { // only for manual checking
runAlertPanel(_mainWindow,
NSLocalizedString(@"Cannot check for update.", nil),
[error localizedDescription],
NSLocalizedString(@"OK", nil), nil, nil);
}
else {
[_movieView setMessage:[error localizedDescription]];
}
}
else if (ret == NO_UPDATE_AVAILABLE) {
NSString* s = NSLocalizedString(@"No update available.", nil);
if (manual) { // only for manual checking
runAlertPanel(_mainWindow, s, @"", NSLocalizedString(@"OK", nil), nil, nil);
}
else {
[_movieView setMessage:s];
}
}
else if (ret == NEW_VERSION_AVAILABLE) {
// new version alert always show.
NSString* newVersion = [checker newVersion];
NSURL* homepageURL = [checker homepageURL];
NSURL* downloadURL = [checker downloadURL];
NSString* s = [NSString stringWithFormat:
NSLocalizedString(@"New version %@ is available.", nil),
newVersion];
ret = runAlertPanel(_mainWindow, s, @"",
NSLocalizedString(@"Show Updates", nil),
NSLocalizedString(@"Download", nil),
NSLocalizedString(@"Cancel", nil));
if (ret == NSAlertDefaultReturn) {
[[NSWorkspace sharedWorkspace] openURL:homepageURL];
}
else if (ret == NSAlertAlternateReturn) {
[[NSWorkspace sharedWorkspace] openURL:downloadURL];
}
}
[checker release];
}
- (IBAction)viewDurationAction:(id)sender
{
//NSLog(@"%s", __PRETTY_FUNCTION__);
_viewDuration = !_viewDuration;
[_defaults setBool:_viewDuration forKey:MViewDurationKey];
[self updateTimeUI];
}
////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark panels
- (IBAction)controlPanelAction:(id)sender
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
if ([_controlPanel isVisible]) {
[_controlPanel hidePanel];
}
else {
[_controlPanel setLevel:[_mainWindow level] + 1];
[_controlPanel showPanel];
//[_controlPanel makeKeyWindow];
}
}
- (IBAction)preferencePanelAction:(id)sender
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
if (!_preferenceController) {
_preferenceController = [[PreferenceController alloc]
initWithAppController:self mainWindow:_mainWindow];
[[_preferenceController window] setDelegate:self];
}
[_preferenceController showWindow:self];
[[_preferenceController window] makeKeyWindow];
[[_preferenceController window] setAlwaysOnTop:[_mainWindow alwaysOnTop]];
[_playPanel orderOutWithFadeOut:self];
}
- (void)setAlwaysOnTopEnabled:(BOOL)enabled
{
_alwaysOnTopEnabled = enabled;
if ([_movieView window] == _mainWindow) {
[self updateAlwaysOnTop:_alwaysOnTopEnabled];
}
}
- (void)updateAlwaysOnTop:(BOOL)alwaysOnTop
{
if ([_movieView window] != _mainWindow) {
return;
}
if (alwaysOnTop) {
alwaysOnTop = ![_defaults boolForKey:MAlwaysOnTopOnPlayingKey] ||
(_movie && [_movie rate] != 0.0);
}
[[_preferenceController window] setAlwaysOnTop:alwaysOnTop];
[[_playlistController window] setAlwaysOnTop:alwaysOnTop];
[_mainWindow setAlwaysOnTop:alwaysOnTop];
[_controlPanel setLevel:[_mainWindow level] + 1];
}
- (IBAction)alwaysOnTopAction:(id)sender
{
//TRACE(@"%s", __PRETTY_FUNCTION__);
_alwaysOnTopEnabled = !_alwaysOnTopEnabled;
NSString* s;
if (_alwaysOnTopEnabled) {
s = NSLocalizedString(@"Keep on Top of All Other Windows", nil);
if ([_defaults boolForKey:MAlwaysOnTopOnPlayingKey]) {
s = [s stringByAppendingFormat:@" (%@)",
NSLocalizedString(@"Apply on Playing Only", nil)];
}
}
else {
s = NSLocalizedString(@"Don't keep on Top of All Other Windows", nil);
}
[_movieView setMessage:s];
[self updateAlwaysOnTop:_alwaysOnTopEnabled];
}
////////////////////////////////////////////////////////////////////////////////
- (void)showOpenAlert:(NSError*)error forURL:(NSURL*)url
{
if ([_movieView window] == _mainWindow) {
runAlertPanelForOpenError(_mainWindow, error, url);
}
else {
[_movieView setError:error
info:[NSString stringWithFormat:@"%@\n\n%@",
NSLocalizedString(@"Cannot open file", nil),
[url isFileURL] ? [url path] : [url absoluteString]]];
}
}
@end
////////////////////////////////////////////////////////////////////////////////
#pragma mark -
@implementation AppController (NSMenuValidation)
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
{
//TRACE(@"%s \"%@\"", __PRETTY_FUNCTION__, [menuItem title]);
if ([[NSApp keyWindow] firstResponder] != _movieView) {
if ([NSApp keyWindow] == [_fullScreener fullWindow]) {
if ([menuItem action] == @selector(fullNavigationAction:)) {
return TRUE;
}
if ([menuItem action] == @selector(prevNextMovieAction:)) {
return ![_fullScreener isNavigating] && (0 < [_playlist count]);
}
if ([menuItem action] == @selector(seekAction:)) {
if ([menuItem tag] == SEEK_TAG_PREV_SUBTITLE ||
[menuItem tag] == SEEK_TAG_NEXT_SUBTITLE) {
return (_movie != nil && _subtitles != nil);
}
else {
return (_movie != nil);
}
}
}
if ([menuItem action] == @selector(fullScreenAction:)) {
return _movie && ![self playlistWindowVisible];
}
if ([menuItem action] == @selector(fullScreenFillAction:)) {
return (_movie != nil);
}
if ([menuItem action] == @selector(desktopBackgroundAction:)) {
return _movie && ![self playlistWindowVisible] && ![self isFullScreen];
}
if ([NSApp keyWindow] == [_playlistController window] &&
[menuItem action] == @selector(playlistAction:)) {
return TRUE;
}
if ([menuItem action] == @selector(openFileAction:)) {
return TRUE;
}
return FALSE;
}
if (![self isFullScreen] &&
[NSApp keyWindow] == [_playlistController window]) {
return FALSE;
}
// File
if ([menuItem action] == @selector(openURLAction:)) {
return FALSE; // not supported yet
}
if ([menuItem action] == @selector(reopenMovieAction:)) {
return (_movie != nil);
}
if ([menuItem action] == @selector(fullNavigationAction:)) {
return [_defaults boolForKey:MFullNavUseKey];
}
// Controls
if ([menuItem action] == @selector(seekAction:)) {
if ([menuItem tag] == 40 || [menuItem tag] == -40) {
return (_movie != nil && _subtitles != nil);
}
else {
return (_movie != nil);
}
}
if ([menuItem action] == @selector(prevNextMovieAction:)) {
return (0 < [_playlist count]);
}
if ([menuItem action] == @selector(rangeRepeatAction:)) {
return (_movie != nil);
}
// Movie
if ([menuItem action] == @selector(movieSizeAction:) ||
[menuItem action] == @selector(fullScreenAction:) ||
[menuItem action] == @selector(fullScreenFillAction:)) {
return (_movie != nil);
}
if ([menuItem action] == @selector(desktopBackgroundAction:)) {
return _movie && ![self isFullScreen];
}
if ([menuItem action] == @selector(aspectRatioAction:)) {
if ([menuItem tag] == ASPECT_RATIO_SAR) {
return (_movie && !NSEqualSizes([_movie displaySize], [_movie encodedSize]));
}
else {
return (_movie != nil);
}
}
if ([menuItem action] == @selector(fullScreenUnderScanAction:)) {
return (_movie && 0 < [_defaults floatForKey:MFullScreenUnderScanKey]);
}
if ([menuItem action] == @selector(audioTrackAction:)) {
return (_movie && 0 < [[_movie audioTracks] count]);
}
if ([menuItem action] == @selector(saveCurrentImage:)) {
return (_movie != nil);
}
// Subtitle
if ([menuItem action] == @selector(openSubtitleFileAction:) ||
[menuItem action] == @selector(addSubtitleFileAction:)) {
return _movie && [_defaults boolForKey:MSubtitleEnableKey];
}
if ([menuItem action] == @selector(reopenSubtitleAction:)) {
return (_subtitles != nil);
}
if ([menuItem action] == @selector(subtitleLanguageAction:)) {
BOOL enabled = (_subtitles && 0 < [_subtitles count]);
if (enabled && [menuItem isAlternate] && ![menuItem state]) {
enabled = ([self enabledSubtitleCount] < 3);
}
return enabled;
}
if ([menuItem action] == @selector(subtitleOrderAction:)) {
return 1 < [_movieView subtitleCount];
}
if ([menuItem action] == @selector(subtitleVisibleAction:) ||
[menuItem action] == @selector(subtitleFontSizeAction:) ||
[menuItem action] == @selector(subtitleVMarginAction:) ||
[menuItem action] == @selector(subtitlePositionAction:) ||
[menuItem action] == @selector(subtitleSyncAction:)) {
return (_subtitles && 0 < [_subtitles count]);
}
// Window
if ([menuItem action] == @selector(alwaysOnTopAction:)) {
[menuItem setState:_alwaysOnTopEnabled];//[_mainWindow alwaysOnTop]];
return ([NSApp keyWindow] == _mainWindow);
}
return TRUE;
}
@end