Updated to version 1.6.5
[MenuTunes.git] / StatusWindowController.m
1 #import "StatusWindowController.h"
2 #import "StatusWindow.h"
3 #import "PreferencesController.h"
4 #import "MainController.h"
5
6 #import <ITKit/ITTSWBackgroundView.h>
7 #import <ITKit/ITWindowEffect.h>
8 #import <ITKit/ITCutWindowEffect.h>
9 #import <ITKit/ITDissolveWindowEffect.h>
10 #import <ITKit/ITSlideHorizontallyWindowEffect.h>
11 #import <ITKit/ITSlideVerticallyWindowEffect.h>
12 #import <ITKit/ITPivotWindowEffect.h>
13
14 static StatusWindowController *sharedController;
15
16 @implementation StatusWindowController
17
18
19 + (StatusWindowController *)sharedController
20 {
21     if ( ! sharedController ) {
22         sharedController = [[StatusWindowController alloc] init];
23     }
24     
25     return sharedController;
26 }
27
28
29 - (id)init
30 {
31     if ( ( self = [super init] ) ) {
32         
33         float exitDelay;
34         NSString *entryClass;
35         NSString *exitClass;
36         NSArray  *classList = [ITWindowEffect effectClasses];
37         float entrySpeed;
38         float exitSpeed;
39                 NSArray *screens = [NSScreen screens];
40                 int screenIndex;
41         
42         NSData *colorData;
43         
44         ITWindowEffect *entryEffect;
45         ITWindowEffect *exitEffect;
46         
47                 _currentType = StatusWindowNoType;
48                 
49         _window = [[StatusWindow sharedWindow] retain];
50         df = [[NSUserDefaults standardUserDefaults] retain];
51         
52         exitDelay  = [df floatForKey:@"statusWindowVanishDelay"];
53         entryClass = [df stringForKey:@"statusWindowAppearanceEffect"];
54         exitClass  = [df stringForKey:@"statusWindowVanishEffect"];
55         entrySpeed = [df floatForKey:@"statusWindowAppearanceSpeed"];
56         exitSpeed  = [df floatForKey:@"statusWindowVanishSpeed"];
57                 
58                 screenIndex = [df integerForKey:@"statusWindowScreenIndex"];
59                 if (screenIndex >= [screens count]) {
60                         screenIndex = 0;
61                 }
62                 [_window setScreen:[screens objectAtIndex:screenIndex]];
63                 
64         [_window setExitMode:ITTransientStatusWindowExitAfterDelay];
65         [_window setExitDelay:(exitDelay ? exitDelay : 4.0)];
66         
67         [_window setHorizontalPosition:[df integerForKey:@"statusWindowHorizontalPosition"]];
68         [_window setVerticalPosition:[df integerForKey:@"statusWindowVerticalPosition"]];
69         
70         [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
71         
72         if ( [classList containsObject:NSClassFromString(entryClass)] ) {
73             entryEffect = [[[NSClassFromString(entryClass) alloc] initWithWindow:_window] autorelease];
74         } else {
75             entryEffect = [[[ITCutWindowEffect alloc] initWithWindow:_window] autorelease];
76         }
77         
78         if ( [classList containsObject:NSClassFromString(exitClass)] ) {
79             exitEffect = [[[NSClassFromString(exitClass) alloc] initWithWindow:_window] autorelease];
80         } else {
81             exitEffect = [[[ITDissolveWindowEffect alloc] initWithWindow:_window] autorelease];
82         }
83         
84         [_window setEntryEffect:entryEffect];
85         [_window setExitEffect:exitEffect];
86         
87         [[_window entryEffect] setEffectTime:(entrySpeed ? entrySpeed : 0.8)];
88         [[_window exitEffect]  setEffectTime:(exitSpeed  ? exitSpeed  : 0.8)];
89         
90         [(ITTSWBackgroundView *)[_window contentView]setBackgroundMode:
91             (ITTSWBackgroundMode)[df integerForKey:@"statusWindowBackgroundMode"]];
92         
93         colorData = [df dataForKey:@"statusWindowBackgroundColor"];
94         
95         if ( colorData ) {
96             [(ITTSWBackgroundView *)[_window contentView] setBackgroundColor:
97                 (NSColor *)[NSUnarchiver unarchiveObjectWithData:colorData]];
98         } else {
99             [(ITTSWBackgroundView *)[_window contentView] setBackgroundColor:[NSColor blueColor]];
100         }
101     }
102     
103     return self;
104 }
105
106 - (void)dealloc
107 {
108     [_window release];
109     [super dealloc];
110 }
111
112 - (void)showSongInfoWindowWithSource:(ITMTRemotePlayerSource)source
113                                title:            (NSString *)title
114                                album:            (NSString *)album
115                               artist:            (NSString *)artist
116                             composer:            (NSString *)composer
117                                 time:            (NSString *)time  // FLOW: Should probably be NSDate or something.
118                                track:            (NSString *)track
119                               rating:                   (int)rating
120                            playCount:                   (int)playCount
121                                image:             (NSImage *)art
122 {
123     NSImage  *image = nil;
124     NSMutableAttributedString *text = [[NSMutableAttributedString alloc] initWithString:title];
125     
126     if ( art != nil ) {
127         image = art;
128     } else if ( source == ITMTRemoteLibrarySource ) {
129         image = [NSImage imageNamed:@"Library"];
130     } else if ( source == ITMTRemoteCDSource ) {
131         image = [NSImage imageNamed:@"CD"];
132     } else if ( source == ITMTRemoteRadioSource ) {
133         image = [NSImage imageNamed:@"Radio"];
134     } else if ( source == ITMTRemoteiPodSource ) {
135         image = [NSImage imageNamed:@"iPod"];
136     } else if ( source == ITMTRemoteGenericDeviceSource ) {
137         image = [NSImage imageNamed:@"MP3Player"];
138     } else if ( source == ITMTRemoteSharedLibrarySource ) {
139         image = [NSImage imageNamed:@"Library"];
140     }
141     
142     [_window setImage:image];
143         [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
144     
145     if ( album ) {
146                 [[text mutableString] appendFormat:@"\n%@", album];
147         //text = [text stringByAppendingString:[@"\n" stringByAppendingString:album]];
148     }
149     if ( artist ) {
150                 [[text mutableString] appendFormat:@"\n%@", artist];
151         //text = [text stringByAppendingString:[@"\n" stringByAppendingString:artist]];
152     }
153     if ( composer ) {
154                 [[text mutableString] appendFormat:@"\n%@", composer];
155         //text = [text stringByAppendingString:[@"\n" stringByAppendingString:composer]];
156     }
157     if ( time ) {
158                 _timeRange = NSMakeRange([[text mutableString] length] + 1, [time length]);
159                 [[text mutableString] appendFormat:@"\n%@", time];
160         //text = [text stringByAppendingString:[@"\n" stringByAppendingString:time]];
161     }
162     if ( track ) {
163                 [[text mutableString] appendFormat:@"\n%@", track];
164         //text = [text stringByAppendingString:[@"\n" stringByAppendingString:track]];
165     }
166     if (playCount > -1) {
167                 [[text mutableString] appendFormat:@"\n%@: %i", NSLocalizedString(@"playCount", @"Play Count"), playCount];
168         //text = [text stringByAppendingString:[NSString stringWithFormat:@"\n%@: %i", NSLocalizedString(@"playCount", @"Play Count"), playCount]];
169     }
170     if ( rating > -1 ) {
171
172         NSString *ratingString = [NSString string];
173         NSString *emptyChar    = [NSString stringWithUTF8String:"☆"];
174         NSString *fullChar     = [NSString stringWithUTF8String:"★"];
175         int       i, start = [[text mutableString] length], size = 18;
176         
177         for ( i = 1; i < 6; i++ ) {
178                 
179             if ( rating >= i ) {
180                 ratingString = [ratingString stringByAppendingString:fullChar];
181             } else {
182                 ratingString = [ratingString stringByAppendingString:emptyChar];
183             }
184         }
185                 
186                 [[text mutableString] appendFormat:@"\n%@", ratingString];
187                 if ([_window sizing] == ITTransientStatusWindowSmall) {
188                         size /= SMALL_DIVISOR;
189                 } else if ([_window sizing] == ITTransientStatusWindowMini) {
190                         size /= MINI_DIVISOR;
191                 }
192                 [text setAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[NSFont fontWithName:@"AppleGothic" size:size], NSFontAttributeName, nil, nil] range:NSMakeRange(start + 1, 5)];
193         //text = [text stringByAppendingString:[@"\n" stringByAppendingString:ratingString]];
194     }
195     
196         _currentType = StatusWindowTrackInfoType;
197     [_window buildTextWindowWithString:text];
198     [_window appear:self];
199         [text release];
200 }
201
202 - (void)showAlbumArtWindowWithImage:(NSImage *)image
203 {
204         if (image) {
205                 _currentType = StatusWindowAlbumArtType;
206                 [_window setImage:[NSImage imageNamed:@"Library"]];
207                 [_window buildImageWindowWithImage:image];
208                 [_window appear:self];
209         }
210 }
211
212 - (void)showAlbumArtWindowWithErrorText:(NSString *)string
213 {
214         if (string && [string length] > 0) {
215                 _currentType = StatusWindowAlbumArtType;
216                 [_window buildTextWindowWithString:string];
217                 [_window appear:self];
218         }
219 }
220
221 - (void)showUpcomingSongsWindowWithTitles:(NSArray *)titleStrings
222 {
223 //  NSString *bull = [NSString stringWithUTF8String:"‣ "];
224     NSString *bull = [NSString stringWithUTF8String:"♪ "];
225     NSString *end  = [@"\n" stringByAppendingString:bull];
226     [_window setImage:[NSImage imageNamed:@"Upcoming"]];
227     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
228     [_window buildTextWindowWithString:[bull stringByAppendingString:[titleStrings componentsJoinedByString:end]]];
229         _currentType = StatusWindowUpcomingSongsType;
230     [_window appear:self];
231 }
232
233 - (void)showVolumeWindowWithLevel:(float)level
234 {
235     [_window setImage:[NSImage imageNamed:@"Volume"]];
236     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
237     [_window buildMeterWindowWithCharacter:[NSString stringWithUTF8String:"▊"]
238                                       size:18
239                                      count:10
240                                     active:( ceil(level * 100) / 10 )];
241         _currentType = StatusWindowVolumeType;
242     [_window appear:self];
243 }
244
245 - (void)showRatingWindowWithRating:(float)rating
246 {
247     [_window setImage:[NSImage imageNamed:@"Rating"]];
248     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
249     [_window buildMeterWindowWithCharacter:[NSString stringWithUTF8String:"★"]
250                                       size:48
251                                      count:5
252                                     active:( ceil(rating * 100) / 20 )];
253     _currentType = StatusWindowRatingType;
254         [_window appear:self];
255 }
256
257 - (void)showShuffleWindow:(BOOL)shuffle
258 {
259     [_window setImage:[NSImage imageNamed:@"Shuffle"]];
260     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
261     [_window buildTextWindowWithString:( shuffle ? NSLocalizedString(@"shuffleOn", @"Shuffle On") : NSLocalizedString(@"shuffleOff", @"Shuffle Off"))];
262         _currentType = StatusWindowRatingType;
263     [_window appear:self];
264 }
265
266 - (void)showRepeatWindowWithMode:(StatusWindowRepeatMode)mode
267 {
268     NSString *string = nil;
269     
270     if ( mode == StatusWindowRepeatNone ) {
271         string = NSLocalizedString(@"repeatOff", @"Repeat Off");
272     } else if ( mode == StatusWindowRepeatGroup ) {
273         string = NSLocalizedString(@"repeatPlaylist", @"Repeat Playlist");
274     } else if ( mode == StatusWindowRepeatTrack ) {
275         string = NSLocalizedString(@"repeatOneTrack", @"Repeat One Track");;
276     }
277     
278     [_window setImage:[NSImage imageNamed:@"Repeat"]];
279     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
280     [_window buildTextWindowWithString:string];
281         _currentType = StatusWindowRepeatType;
282     [_window appear:self];
283 }
284
285 - (void)showSongShufflabilityWindow:(BOOL)shufflable
286 {
287     [_window setImage:[NSImage imageNamed:@"Shuffle"]];
288     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
289     [_window buildTextWindowWithString:( !shufflable ? NSLocalizedString(@"shufflableOn", @"Current Song Skipped When Shuffling") : NSLocalizedString(@"shufflableOff", @"Current Song Not Skipped When Shuffling"))];
290         _currentType = StatusWindowShufflabilityType;
291     [_window appear:self];
292 }
293
294 - (void)showSetupQueryWindow
295 {
296     NSString *message = NSLocalizedString(@"autolaunch_msg", @"Would you like MenuTunes to launch\nautomatically at startup?");
297
298     [_window setImage:[NSImage imageNamed:@"Setup"]];
299     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
300     [_window buildDialogWindowWithMessage:message
301                             defaultButton:NSLocalizedString(@"launch_at_startup", @"Launch at Startup")
302                           alternateButton:NSLocalizedString(@"launch_manually", @"Launch Manually")
303                                    target:[PreferencesController sharedPrefs]
304                             defaultAction:@selector(autoLaunchOK)
305                           alternateAction:@selector(autoLaunchCancel)];
306
307         _currentType = StatusWindowSetupType;
308     [_window appear:self];
309     [_window setLocked:YES];
310 }
311
312
313 - (void)showRegistrationQueryWindow
314 {
315     NSString *message = NSLocalizedString(@"trialexpired_msg", @"Your 7-day unlimited trial period has elapsed.\nYou must register to continue using MenuTunes.");
316
317     [_window setImage:[NSImage imageNamed:@"Register"]];
318     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
319     [_window buildDialogWindowWithMessage:message
320                             defaultButton:NSLocalizedString(@"registernow", @"Register Now")
321                           alternateButton:NSLocalizedString(@"quitmenutunes", @"Quit MenuTunes")
322                                    target:[MainController sharedController]
323                             defaultAction:@selector(registerNowOK)
324                           alternateAction:@selector(registerNowCancel)];
325
326         _currentType = StatusWindowRegistrationType;
327     [_window appear:self];
328     [_window setLocked:YES];
329 }
330
331 - (void)showReconnectQueryWindow
332 {
333     NSString *message = NSLocalizedString(@"sharedplayeravailable_msg", @"The selected shared player is available again.\nWould you like to reconnect to it?");
334     [_window setLocked:NO];
335     [_window setImage:[NSImage imageNamed:@"Setup"]];
336     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
337     [_window buildDialogWindowWithMessage:message
338                             defaultButton:NSLocalizedString(@"reconnect", @"Reconnect")
339                           alternateButton:NSLocalizedString(@"ignore", @"Ignore")
340                                    target:[MainController sharedController]
341                             defaultAction:@selector(reconnect)
342                           alternateAction:@selector(cancelReconnect)];
343
344         _currentType = StatusWindowNetworkType;
345     [_window appear:self];
346     [_window setLocked:YES];
347 }
348
349 - (void)showNetworkErrorQueryWindow
350 {
351     NSString *message = NSLocalizedString(@"sharedplayerunreachable_msg", @"The remote MenuTunes server is unreachable.\nMenuTunes will revert back to the local player.");
352
353     [_window setImage:[NSImage imageNamed:@"Setup"]];
354     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
355     [_window buildDialogWindowWithMessage:message
356                             defaultButton:@" OK "
357                           alternateButton:nil
358                                    target:[MainController sharedController]
359                             defaultAction:@selector(cancelReconnect)
360                           alternateAction:nil];
361
362         _currentType = StatusWindowNetworkType;
363     [_window appear:self];
364     [_window setLocked:YES];
365 }
366
367 - (void)showPreferencesUpdateWindow
368 {
369     NSString *message = NSLocalizedString(@"reconfigureprefs_msg", @"The new features in this version of MenuTunes\nrequire you to reconfigure your preferences.");
370
371     [_window setImage:[NSImage imageNamed:@"Setup"]];
372     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
373     [_window buildDialogWindowWithMessage:message
374                             defaultButton:NSLocalizedString(@"showpreferences", @"Show Preferences")
375                           alternateButton:@"OK"
376                                    target:[MainController sharedController]
377                             defaultAction:@selector(showPreferencesAndClose)
378                           alternateAction:@selector(cancelReconnect)];
379
380         _currentType = StatusWindowPreferencesType;
381     [_window appear:self];
382     [_window setLocked:YES];
383 }
384
385 - (void)showDebugModeEnabledWindow
386 {
387         [_window setImage:[NSImage imageNamed:@"Setup"]];
388     [_window setSizing:(ITTransientStatusWindowSizing)[df integerForKey:@"statusWindowSizing"]];
389     [_window buildDialogWindowWithMessage:NSLocalizedString(@"debugmodeenabled", @"Debug Mode Enabled")
390                             defaultButton:@"OK"
391                           alternateButton:nil
392                                    target:[MainController sharedController]
393                             defaultAction:@selector(cancelReconnect)
394                           alternateAction:nil];
395
396         _currentType = StatusWindowDebugType;
397     [_window appear:self];
398         [_window setLocked:YES];
399 }
400
401 - (StatusWindowType)currentStatusWindowType
402 {
403         return _currentType;
404 }
405
406 - (void)updateTime:(NSString *)time
407 {
408         if (time && [time length]) {
409                 [_window updateTime:time range:_timeRange];
410         }
411 }
412
413 @end