1/*
2   Project: MPDCon
3
4   Copyright (C) 2012
5
6   Author: Sebastian Reitenbach
7
8   Created: 2012-10-31
9
10   Playlist Inspector
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 <AppKit/AppKit.h>
28#include "PlaylistInspector.h"
29#include "SongRatingCell.h"
30#include "Strings.h"
31#include "CollectionController.h"
32
33@implementation PlaylistInspector
34
35+ (id) sharedPlaylistInspector
36{
37  static PlaylistInspector *_sharedPlaylistInspector = nil;
38
39  if (! _sharedPlaylistInspector) {
40      _sharedPlaylistInspector =
41	[[PlaylistInspector allocWithZone: [self zone]] init];
42  }
43
44  return _sharedPlaylistInspector;
45}
46
47- (id) init
48{
49  if ((self = [self initWithWindowNibName: @"PlaylistInspector"]) != nil)
50    {
51      [self setWindowFrameAutosaveName: @"PlaylistInspector"];
52      defaults = [NSUserDefaults standardUserDefaults];
53      mpdController = [MPDController sharedMPDController];
54      playlistController = [PlaylistController sharedPlaylistController];
55      threadlock = [NSLock new];
56    }
57  return self;
58}
59
60- (void) dealloc
61{
62  [minRatingCol release];
63  [maxRatingCol release];
64  [defaults release];
65  [threadlock release];
66
67  [super dealloc];
68}
69
70/* GUI methods */
71- (void) awakeFromNib
72{
73  NSNotificationCenter *defCenter;
74
75  SongRatingCell *minRatingCell;
76  SongRatingCell *maxRatingCell;
77
78  ASSIGN(minRatingCol, [minRatingStars tableColumnWithIdentifier: @"minrating"]);
79  ASSIGN(maxRatingCol, [maxRatingStars tableColumnWithIdentifier: @"maxrating"]);
80  [minRatingStars setAutosaveName: @"MinRatingStarsTable"];
81  [minRatingStars setAutosaveTableColumns: YES];
82  [minRatingStars setHeaderView: nil];
83  [minRatingStars setTarget:self];
84  [maxRatingStars setAutosaveName: @"MaxRatingStarsTable"];
85  [maxRatingStars setAutosaveTableColumns: YES];
86  [maxRatingStars setHeaderView: nil];
87  [maxRatingStars setTarget:self];
88
89  defCenter = [NSNotificationCenter defaultCenter];
90  [defCenter addObserver: self
91                selector: @selector(songChanged:)
92                    name: SongChangedNotification
93                  object: nil];
94  [defCenter addObserver: self
95                selector: @selector(playlistChanged:)
96                    name: PlaylistChangedNotification
97                  object: nil];
98
99  minRatingCell = [[SongRatingCell alloc] init];
100  maxRatingCell = [[SongRatingCell alloc] init];
101  [minRatingCol setDataCell:minRatingCell];
102  [maxRatingCol setDataCell:maxRatingCell];
103
104  [randomPlaylistFeed setState: [defaults integerForKey: @"RandomPlaylistFeed"]];
105  [ratingBasedFeed setState: [defaults integerForKey: @"RatingBasedFeed"]];
106  [includeUnratedSongs setState: [defaults integerForKey: @"IncludeUnratedSongs"]];
107  [nrNewSongs setStringValue:  [NSString stringWithFormat:@"%"PRIiPTR, [defaults integerForKey: @"NrOfFutureSongs"]?
108		[defaults integerForKey: @"NrOfFutureSongs"]:20]];
109  [nrPlayedSongs setStringValue: [NSString stringWithFormat:@"%"PRIiPTR, [defaults integerForKey: @"NrOfOldSongsToKeep"]?
110		[defaults integerForKey: @"NrOfOldSongsToKeep"]:20]];
111
112  if (![randomPlaylistFeed state])
113    {
114      [nrNewSongs setEditable: NO];
115      [nrPlayedSongs setEditable: NO];
116      [nrOfNewSongsText setEnabled: NO];
117      [nrOfPlayedSongsText setEnabled: NO];
118      [ratingBasedFeed setEnabled:NO];
119      [minRatingText setEnabled: NO];
120      [maxRatingText setEnabled: NO];
121      [includeUnratedSongs setEnabled:NO];
122      // the stuff below doesn't work like expected, also setEnabled: NO doesn't seem to work either
123      [minRatingCell setEditable: NO];
124      [maxRatingCell setEditable: NO];
125    }
126  else
127    {
128      if (![ratingBasedFeed state])
129	{
130          // the stuff below doesn't work like expected
131	  // also setEnabled: NO doesn't seem to work either
132          [minRatingText setEnabled: NO];
133          [maxRatingText setEnabled: NO];
134          [minRatingCell setEditable: NO];
135          [maxRatingCell setEditable: NO];
136          [includeUnratedSongs setEnabled:NO];
137	}
138    }
139  [self updatePlaylistInspector];
140  RELEASE(minRatingCell);
141  RELEASE(maxRatingCell);
142}
143
144- (void) nrOfFutureSongsChanged: (id) sender
145{
146  [defaults setInteger: [nrNewSongs integerValue] forKey:@"NrOfFutureSongs"];
147  [defaults synchronize];
148  [self sendRandomPlaylistFeedDefaultsChangedNotification];
149}
150- (void) nrOfOldSongsToKeepChanged: (id) sender
151{
152  [defaults setInteger: [nrPlayedSongs integerValue] forKey:@"NrOfOldSongsToKeep"];
153  [defaults synchronize];
154  [self sendRandomPlaylistFeedDefaultsChangedNotification];
155}
156- (void) randomPlaylistFeedStateChanged: (id) sender
157{
158  [defaults setInteger: [randomPlaylistFeed state] forKey:@"RandomPlaylistFeed"];
159  [defaults synchronize];
160  [self sendRandomPlaylistFeedDefaultsChangedNotification];
161  if ([randomPlaylistFeed state])
162    {
163      [nrNewSongs setEditable: YES];
164      [nrPlayedSongs setEditable: YES];
165      [nrOfNewSongsText setEnabled: YES];
166      [nrOfPlayedSongsText setEnabled: YES];
167      [ratingBasedFeed setEnabled:YES];
168      if ([ratingBasedFeed state])
169        {
170          [minRatingStars setEnabled: YES];
171          [maxRatingStars setEnabled: YES];
172          [minRatingText setEnabled: YES];
173          [maxRatingText setEnabled: YES];
174          [includeUnratedSongs setEnabled:YES];
175        }
176    }
177  else
178    {
179      [nrNewSongs setEditable: NO];
180      [nrPlayedSongs setEditable: NO];
181      [nrOfNewSongsText setEnabled: NO];
182      [nrOfPlayedSongsText setEnabled: NO];
183      [ratingBasedFeed setEnabled:NO];
184      // the stuff below doesn't work like expected, also setEnabled: NO doesn't seem to work either
185      [maxRatingStars setEnabled: NO];
186      [minRatingStars setEnabled: NO];
187      [minRatingText setEnabled: NO];
188      [maxRatingText setEnabled: NO];
189      [includeUnratedSongs setEnabled:NO];
190    }
191}
192- (void) ratingBasedFeedStateChanged: (id) sender
193{
194  [defaults setInteger: [ratingBasedFeed state] forKey:@"RatingBasedFeed"];
195  [defaults synchronize];
196  [self sendRandomPlaylistFeedDefaultsChangedNotification];
197  // the disabling is not working, they seem to be always enabled
198  if ([ratingBasedFeed state])
199    {
200      [maxRatingStars setEnabled: YES];
201      [minRatingStars setEnabled: YES];
202      [minRatingText setEnabled: YES];
203      [maxRatingText setEnabled: YES];
204      [includeUnratedSongs setEnabled:YES];
205    }
206  else
207    {
208      [maxRatingStars setEnabled: NO];
209      [minRatingStars setEnabled: NO];
210      [minRatingText setEnabled: NO];
211      [maxRatingText setEnabled: NO];
212      [includeUnratedSongs setEnabled:NO];
213    }
214}
215
216- (void) includeUnratedSongsChanged: (id) sender
217{
218  [defaults setInteger: [includeUnratedSongs state] forKey:@"IncludeUnratedSongs"];
219  [defaults synchronize];
220  [self sendRandomPlaylistFeedDefaultsChangedNotification];
221}
222
223/* the delegate methods */
224- (void) songChanged:(NSNotification *)aNotif
225{
226  [self updateCurrentSongNr];
227}
228
229- (void) playlistChanged:(NSNotification *)aNotif
230{
231  [self updatePlaylistInfo];
232}
233
234- (void) updateCurrentSongNr
235{
236  [currentSongNr setStringValue:[NSString stringWithFormat:@"%i", [mpdController getCurrentSongNr]]];
237}
238
239- (void) updatePlaylistInfo
240{
241  [playlistPlayingTime setStringValue: [playlistController playlistLength]];
242  [nrOfSongsInPlaylist setStringValue: [NSString stringWithFormat:@"%i", [mpdController getPlaylistLength]]];
243  [self updateCurrentSongNr];
244}
245
246
247
248- (void) updatePlaylistInspector
249{
250  [minRatingStars reloadData];
251  [maxRatingStars reloadData];
252  [playlistPlayingTime setStringValue: [playlistController playlistLength]];
253  [currentSongNr setStringValue:[NSString stringWithFormat:@"%i", [mpdController getCurrentSongNr]]];
254  [nrOfSongsInPlaylist setStringValue: [NSString stringWithFormat:@"%i", [mpdController getPlaylistLength]]];
255  return;
256}
257
258- (NSInteger) numberOfRowsInTableView: (NSTableView *)tableView
259{
260    return 1;
261}
262
263-          (id) tableView: (NSTableView *) tableView
264objectValueForTableColumn: (NSTableColumn *) tableColumn
265		      row: (NSInteger) row
266{
267  NSString *identifier;
268
269  identifier = [tableColumn identifier];
270
271  if ([identifier isEqual:@"minrating"])
272    {
273      return [NSNumber numberWithInteger:
274	[defaults integerForKey: @"RandomPlaylistMinRating"]];
275    }
276  else
277    {
278      return [NSNumber numberWithInteger:
279	[defaults integerForKey: @"RandomPlaylistMaxRating"]?[defaults integerForKey: @"RandomPlaylistMaxRating"]:5];
280    }
281}
282
283// method below doesn't get called, its actually intended
284// to disable the editing of the rating stars...
285- (BOOL) tableView: (NSTableView *) tableView
286shouldEditTableColumn: (NSTableColumn *)aTableColumn
287	       row:(NSInteger)rowIndex
288{
289  if ([randomPlaylistFeed state] && [ratingBasedFeed state])
290    {
291      return YES;
292    }
293  else
294    {
295      return NO;
296    }
297}
298
299
300-(void) tableView: (NSTableView *) aTableView
301   setObjectValue: (id) anObj
302   forTableColumn: (NSTableColumn *) aTableColumn
303              row: (NSInteger) rowIndex
304{
305    if (aTableColumn == minRatingCol) {
306        /* We can't keep that as an assertion now, as it can easily fail when
307         * the broken GNUstep NSTableView lets you edit the string value for the cell.
308         */
309        if ([anObj isKindOfClass: [NSNumber class]] == NO) {
310            NSLog(@"Warning: %@ is not a number value.", anObj);
311        }
312	[defaults setInteger: [anObj intValue] forKey:@"RandomPlaylistMinRating"];
313    } else if (aTableColumn == maxRatingCol) {
314        /* We can't keep that as an assertion now, as it can easily fail when
315         * the broken GNUstep NSTableView lets you edit the string value for the cell.
316         */
317        if ([anObj isKindOfClass: [NSNumber class]] == NO) {
318            NSLog(@"Warning: %@ is not a number value.", anObj);
319        }
320	[defaults setInteger: [anObj intValue] forKey:@"RandomPlaylistMaxRating"];
321    }
322    [defaults synchronize];
323    [self sendRandomPlaylistFeedDefaultsChangedNotification];
324}
325
326- (void) sendRandomPlaylistFeedDefaultsChangedNotification
327{
328  NSNotification *aNotif;
329  aNotif = [NSNotification notificationWithName:
330			RandomPlaylistFeedDefaultsChangedNotification
331                        object: nil];
332  [[NSNotificationCenter defaultCenter]
333    postNotification: aNotif];
334}
335@end
336