1/*
2   Project: MPDCon
3
4   Copyright (C) 2004
5
6   Author: Daniel Luederwald
7
8   Created: 2004-05-12 17:59:14 +0200 by flip
9
10   Application Controller
11
12   This application is free software; you can redistribute it and/or
13   modify it under the terms of the GNU General Public
14   License as published by the Free Software Foundation; either
15   version 2 of the License, or (at your option) any later version.
16
17   This application is distributed in the hope that it will be useful,
18   but WITHOUT ANY WARRANTY; without even the implied warranty of
19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20   Library General Public License for more details.
21
22   You should have received a copy of the GNU General Public
23   License along with this library; if not, write to the Free
24   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
25*/
26
27#include "AppController.h"
28
29/* ---------------------
30   - Private Interface -
31   ---------------------*/
32
33@interface AppController(Private)
34
35- (void) _updateView: (id)sender;
36
37@end
38
39@implementation AppController
40
41/* --------------------------
42   - Initialization Methods -
43   --------------------------*/
44
45- (void) dealloc
46{
47  [mpdController release];
48  [anTimer release];
49  [randomPlaylistFeed release];
50
51  [super dealloc];
52
53}
54
55/* ---------------
56   - Gui Methods -
57   ---------------*/
58
59- (void) awakeFromNib
60{
61  NSNotificationCenter *defCenter;
62  BOOL reversedTime;
63
64  defCenter = [NSNotificationCenter defaultCenter];
65
66  [[NSApp mainMenu] setTitle:@"MPDCon"];
67
68  [window setFrameAutosaveName: @"PlayerWindow"];
69
70  mpdController = [MPDController sharedMPDController];
71  randomPlaylistFeed = [[RandomPlaylistFeed alloc] init];
72
73  prevState = state_NOCONN;
74
75  [defCenter addObserver: self
76		selector: @selector(didDisconnect:)
77		    name: DidNotConnectNotification
78		  object: nil];
79
80  [defCenter addObserver: self
81		selector: @selector(didConnect:)
82		    name: DidConnectNotification
83		  object: nil];
84
85  [defCenter addObserver: self
86		selector: @selector(prefsChanged:)
87		    name: PreferencesChangedNotification
88		  object: nil];
89
90  didDisconnect = NO;
91
92  [self connect: self];
93
94  reversedTime = [[NSUserDefaults standardUserDefaults]
95		   boolForKey: @"reversedTime"];
96
97  [playView setReversedTime: reversedTime];
98}
99
100- (void) showPrefPanel: (id)sender
101{
102  [[PreferencesController sharedPreferencesController] showWindow: sender];
103}
104
105- (void) showLyricsInspector: (id)sender
106{
107  if (! connected)
108    {
109      return;
110    }
111
112  [[LyricsInspector sharedLyricsInspector] showWindow: sender];
113}
114
115- (void) showSongInspector: (id)sender
116{
117  if (! connected)
118    {
119      return;
120    }
121
122  [[SongInspector sharedSongInspector] showWindow: sender];
123}
124
125- (void) showPlaylistInspector: (id)sender
126{
127  if (! connected)
128    {
129      return;
130    }
131  [[PlaylistInspector sharedPlaylistInspector] showWindow: sender];
132}
133
134
135- (void) showPlaylist: (id)sender
136{
137  if (! connected)
138    {
139      return;
140    }
141
142  [[PlaylistController sharedPlaylistController] showWindow: sender];
143}
144
145- (void) managePlaylists: (id)sender
146{
147  if (! connected)
148    {
149      return;
150    }
151
152  [[PlaylistsManagerController sharedPLManagerController] showWindow: sender];
153}
154
155- (void) browseCollection: (id)sender
156{
157  if (! connected)
158    {
159      return;
160    }
161
162  [[CollectionController sharedCollectionController] showWindow: self];
163}
164
165- (void) browseCollectionByDirectory: (id)sender
166{
167  if (! connected)
168    {
169      return;
170    }
171
172  [[CollectionBrowser sharedCollectionBrowser] showWindow: self];
173}
174
175- (void) serverStatistics: (id)sender
176{
177  if (! connected)
178    {
179      return;
180    }
181
182  [[StatisticsController sharedStatisticsController] showWindow: sender];
183}
184
185- (void) showCrossfade: (id)sender
186{
187  if (! connected)
188    {
189      return;
190    }
191
192  [[CrossfadeController sharedCrossfadeController] showWindow: sender];
193}
194
195- (void) connect: (id)sender
196{
197  NSString *host;
198  NSString *port;
199  NSString *pword;
200  NSString *tout;
201
202  host = [[NSUserDefaults standardUserDefaults]
203	   objectForKey: @"mpdHost"];
204  port = [[NSUserDefaults standardUserDefaults]
205	   objectForKey: @"mpdPort"];
206  tout = [[NSUserDefaults standardUserDefaults]
207	   objectForKey: @"mpdTimeout"];
208  pword = nil;
209
210  if ([[NSUserDefaults standardUserDefaults]
211	integerForKey: @"usePassword"] != 0)
212    {
213      pword = [[NSUserDefaults standardUserDefaults]
214		objectForKey: @"mpdPassword"];
215    }
216
217  if ((host == nil) || (port == nil) || (tout == nil))
218    {
219      [self showPrefPanel: self];
220    }
221  else
222    {
223      didDisconnect = NO;
224      [mpdController connectToServer: host port: port password: pword timeout: tout];
225    }
226}
227
228- (void) updateCollection: (id) sender
229{
230  [mpdController updateCollection];
231}
232
233- (void) play: (id)sender
234{
235  if (! connected)
236    {
237    return;
238    }
239
240  [mpdController play];
241}
242
243- (void) stop: (id)sender
244{
245  if (! connected)
246    {
247      return;
248    }
249
250  [mpdController stop];
251}
252
253- (void) prev: (id)sender
254{
255  if (! connected)
256    {
257      return;
258    }
259
260  [mpdController prev];
261}
262
263- (void) next: (id)sender
264{
265  if (! connected)
266    {
267      return;
268    }
269
270  [mpdController next];
271}
272
273- (void) shuffle: (id)sender
274{
275  if (! connected)
276    return;
277  [mpdController toggleShuffle];
278}
279
280- (void) repeat: (id)sender
281{
282  if (! connected)
283    {
284      return;
285    }
286
287  [mpdController toggleRepeat];
288}
289
290- (void) percentChanged: (id)sender
291{
292  int seekTime;
293
294  if (! connected)
295    {
296      [percentSlider setFloatValue: 0.0];
297      return;
298    }
299
300  if ([mpdController getState] == state_NOCONN)
301    {
302      [percentSlider setFloatValue: 0.0];
303      return;
304    }
305
306  seekTime = (int) [percentSlider floatValue];
307
308  [mpdController seekToTime: seekTime];
309
310  [playView setElapsedTime: seekTime];
311}
312
313- (void) volumeChanged: (id)sender
314{
315  if ((! connected) || ([mpdController getState] == state_NOCONN))
316    {
317      [volumeSlider setFloatValue: 0.0];
318      return;
319    }
320
321  [mpdController setVolume: [volumeSlider floatValue]];
322}
323
324/* ------------------------
325   - Notification Methods -
326   ------------------------*/
327
328- (void) didDisconnect: (NSNotification *)notif
329{
330  if (!didDisconnect)
331    {
332      didDisconnect = YES;
333      if (connected)
334	{
335	  if (anTimer)
336	    {
337	      [anTimer invalidate];
338	    }
339	}
340
341      connected = NO;
342
343      [playView enableDisplay: NO];
344
345      [playButton setImage: [NSImage imageNamed: @"Play.tiff"]];
346
347      [percentSlider setFloatValue: 0.0];
348
349      NSRunAlertPanel(_(@"Server Problems"), [notif object], nil, nil, nil);
350    }
351}
352
353- (void) didConnect: (NSNotification *)aNotif
354{
355  if (! connected)
356    {
357      connected = YES;
358      anTimer = [NSTimer scheduledTimerWithTimeInterval: 1
359			                         target: self
360                                               selector:
361			                            @selector(_updateView:)
362			                       userInfo: nil
363			                        repeats: YES];
364    }
365
366  didDisconnect = NO;
367}
368
369
370- (void) prefsChanged: (NSNotification *)notif
371{
372  [self connect: self];
373}
374
375/* -------------------
376   - Service Methods -
377   -------------------*/
378
379- (void) getPlaylist: (NSPasteboard*)pboard
380	    userData: (NSString*)userData
381	       error: (NSString**)error
382{
383  NSMutableString *allSongsString;
384  NSString *formString;
385  NSArray *playlist;
386  int length;
387  int totaltime, tMin, tSecs, tHour;
388
389  int i, j;
390
391  allSongsString = [[NSMutableString alloc] init];
392
393  playlist = [mpdController getPlaylist];
394
395  length = [[NSString stringWithFormat: @"%"PRIuPTR, [playlist count]] length];
396
397  formString = [NSString stringWithFormat: @"Track %s%d%s - ",
398		 "%", length, "d/%d"];
399
400  j = [playlist count];
401
402  totaltime = 0;
403  for (i = 0; i < j; i++)
404    {
405      int time;
406
407      [allSongsString appendString:
408			[NSString stringWithFormat: formString, i+1, j]];
409      [allSongsString appendString: [[playlist objectAtIndex: i] getArtist]];
410      [allSongsString appendString: @" - "];
411      [allSongsString appendString: [[playlist objectAtIndex: i] getTitle]];
412      [allSongsString appendString: @" - "];
413
414      time = [[playlist objectAtIndex: i] getTotalTime];
415
416      totaltime += time;
417
418      tSecs = (time % 60);
419      tMin = (int) time/60;
420
421      [allSongsString appendString:
422			[NSString stringWithFormat: @"%d:%02d\n",
423				  tMin, tSecs]];
424    }
425
426  tSecs = (totaltime % 60);
427  tMin = (int) (totaltime/60) % 60;
428  tHour = (int) totaltime/3600;
429
430  [allSongsString appendString:
431		    [NSString stringWithFormat:
432			      @"\nTotal Playtime: %d:%02d:%02d\n",
433			      tHour, tMin, tSecs]];
434
435  [pboard declareTypes: [NSArray arrayWithObject: NSStringPboardType]
436	         owner: nil];
437
438  [pboard setString: allSongsString forType: NSStringPboardType];
439  RELEASE(allSongsString);
440  return;
441}
442
443- (void) getAlbums: (NSPasteboard*)pboard
444	  userData: (NSString*)userData
445	     error: (NSString**)error
446{
447  NSMutableString *allAlbumsString;
448  NSArray *artists;
449
450  int i;
451
452  allAlbumsString = [[NSMutableString alloc] init];
453
454  artists = [mpdController getAllArtists];
455
456  for (i = 0; i < [artists count]; i++)
457    {
458      NSString *artist;
459      NSArray *albums;
460
461      int j;
462
463      artist = [artists objectAtIndex: i];
464
465      albums = [mpdController getAlbumsForArtist: artist];
466
467      for (j = 0; j < [albums count]; j++)
468	{
469	  NSString *album;
470
471	  album = [albums objectAtIndex: j];
472
473	  [allAlbumsString appendString:
474			     [NSString stringWithFormat: @"%@ - %@\n",
475				       artist, album]];
476	}
477    }
478
479  [pboard declareTypes: [NSArray arrayWithObject: NSStringPboardType]
480	         owner: nil];
481
482  [pboard setString: allAlbumsString forType: NSStringPboardType];
483  RELEASE(allAlbumsString);
484  return;
485}
486
487/* --------------------------------
488   - Application Delegate Methods -
489   --------------------------------*/
490
491- (void) applicationDidFinishLaunching: (NSNotification *)not
492{
493  [NSApp setServicesProvider: self];
494}
495
496
497
498 - (BOOL) validateMenuItem: (id<NSMenuItem>)menuItem
499{
500
501  switch ([menuItem tag])
502    {
503    case 10:
504    case 14:
505    case 15:
506    case 16:
507    case 17:
508    case 18:
509      return connected;
510      break;
511    case 13:
512      return didDisconnect;
513      break;
514    default:
515      return YES;
516      break;
517    }
518
519}
520
521@end
522
523
524/* -------------------
525   - Private Methods -
526   -------------------*/
527 @implementation AppController(Private)
528
529- (void) _updateView: (id)sender
530{
531  int state;
532
533  if (! connected) {
534      return;
535  }
536
537  if ([mpdController getState] == state_NOCONN) {
538      return;
539  }
540  if ([mpdController getState] == state_UNKNOWN) {
541      return;
542  }
543
544  if ([mpdController playlistChanged]) {
545      NSNotification *aNotif;
546
547      aNotif = [NSNotification notificationWithName:
548				      PlaylistChangedNotification
549			                     object: nil];
550
551      [[NSNotificationCenter defaultCenter]
552	postNotification: aNotif];
553  }
554
555  if ([mpdController isRandom]) {
556      [shuffleButton setState: YES];
557  } else {
558      [shuffleButton setState: NO];
559  }
560
561  if ([mpdController isRepeat]) {
562      [repeatButton setState: YES];
563  } else {
564      [repeatButton setState: NO];
565  }
566
567  [volumeSlider setIntValue: [mpdController getVolume]];
568
569  state = [mpdController getState];
570
571  if((state == state_PLAY) || (state == state_PAUSE)) {
572      PlaylistItem *currSong;
573
574      int currentSongNr;
575      int playlistLength;
576
577
578      currentSongNr = [mpdController getCurrentSongNr];
579
580      playlistLength = [mpdController getPlaylistLength];
581
582      currSong = [[mpdController getCurrentSong] retain];
583
584      if (currentSongNr != playedSong) {
585	  playedSong = currentSongNr;
586	  if ([currSong getTotalTime] != 0) {
587	      [percentSlider setMaxValue: (double) [currSong getTotalTime]];
588	  }
589
590	  [[NSNotificationCenter defaultCenter]
591	    postNotification: [NSNotification
592				notificationWithName: SongChangedNotification
593				              object: nil]];
594      }
595
596      [playView enableDisplay: YES];
597
598      [playView setCurrentSong: currentSongNr];
599      [playView setTotalSongs: playlistLength];
600
601      if((state == state_PAUSE) && (prevState != state_PAUSE)) {
602	  NSImage *pImage;
603
604	  prevState = state_PAUSE;
605
606	  pImage = [NSImage imageNamed: @"Play.tiff"];
607
608	  [playButton setImage: pImage];
609
610      }
611      else if ((state == state_PLAY) &&(prevState != state_PLAY)) {
612	  NSImage *pImage;
613
614	  prevState = state_PLAY;
615
616	  pImage = [NSImage imageNamed: @"Pause.tiff"];
617
618	  [playButton setImage: pImage];
619
620	  [[NSNotificationCenter defaultCenter]
621	    postNotification: [NSNotification
622				notificationWithName: SongChangedNotification
623				              object: nil]];
624      }
625
626      [playView setDisplaySong: currSong];
627
628      if ([currSong getTotalTime] != 0) {
629	  [percentSlider setDoubleValue: (double)[currSong getElapsedTime]];
630      }
631
632      [currSong release];
633  } else if (prevState != state_STOP) {
634      NSImage *pImage;
635
636      prevState = state_STOP;
637
638      pImage = [NSImage imageNamed: @"Play.tiff"];
639      [playButton setImage: pImage];
640
641      [playButton setTitle: @"Play"];
642
643      [percentSlider setFloatValue: 0.0];
644
645      [playView enableDisplay: NO];
646
647      [[NSNotificationCenter defaultCenter]
648	postNotification: [NSNotification
649			    notificationWithName: SongChangedNotification
650			                  object: nil]];
651  }
652
653}
654
655@end
656