1 #import "PreferencesController.h"
2 #import "MainController.h"
3 #import "HotKeyCenter.h"
5 @implementation PreferencesController
7 - (id)initWithMenuTunes:(MainController *)tunes;
9 if ( (self = [super init]) ) {
11 NSImageCell *imgCell = [[[NSImageCell alloc] init] autorelease];
12 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
15 [mt registerDefaults];
17 [NSBundle loadNibNamed:@"Preferences" owner:self]; //Load the nib
19 //Set the table view cells up
20 [imgCell setImageScaling:NSScaleNone];
21 [[menuTableView tableColumnWithIdentifier:@"submenu"] setDataCell:imgCell];
22 [[allTableView tableColumnWithIdentifier:@"submenu"] setDataCell:imgCell];
24 //Register for drag and drop
25 [menuTableView registerForDraggedTypes:[NSArray arrayWithObjects:@"MenuTableViewPboardType", @"AllTableViewPboardType", nil]];
26 [allTableView registerForDraggedTypes:[NSArray arrayWithObjects:@"MenuTableViewPboardType", @"AllTableViewPboardType", nil]];
28 //Set the list of items you can have.
29 availableItems = [[NSMutableArray alloc] initWithObjects:@"Current Track Info", @"Upcoming Songs", @"Playlists", @"EQ Presets", @"Song Rating", @"Play/Pause", @"Next Track", @"Previous Track", @"Fast Forward", @"Rewind", @"<separator>", nil];
31 //Get our preferred menu
32 myItems = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"menu"] mutableCopy];
34 //Delete items in the availableItems array that are already part of the menu
35 for (i = 0; i < [myItems count]; i++) {
36 NSString *item = [myItems objectAtIndex:i];
37 if (![item isEqualToString:@"<separator>"])
39 [availableItems removeObject:item];
43 //Items that show should a submenu image
44 submenuItems = [[NSArray alloc] initWithObjects:@"Upcoming Songs", @"Playlists", @"EQ Presets", @"Song Rating", nil];
46 //Fill in the number of songs in advance to show field
47 [songsInAdvance setIntValue:[defaults integerForKey:@"SongsInAdvance"]];
49 //Fill in hot key buttons
50 if ([defaults objectForKey:@"PlayPause"]){
51 playPauseCombo = [defaults keyComboForKey:@"PlayPause"];
52 [playPauseButton setTitle:[playPauseCombo userDisplayRep]];
54 playPauseCombo = [[KeyCombo alloc] init];
57 if ([defaults objectForKey:@"NextTrack"]) {
58 nextTrackCombo = [defaults keyComboForKey:@"NextTrack"];
59 [nextTrackButton setTitle:[nextTrackCombo userDisplayRep]];
61 nextTrackCombo = [[KeyCombo alloc] init];
64 if ([defaults objectForKey:@"PrevTrack"]) {
65 prevTrackCombo = [defaults keyComboForKey:@"PrevTrack"];
66 [previousTrackButton setTitle:[prevTrackCombo userDisplayRep]];
68 prevTrackCombo = [[KeyCombo alloc] init];
71 if ([defaults objectForKey:@"TrackInfo"]) {
72 trackInfoCombo = [defaults keyComboForKey:@"TrackInfo"];
73 [trackInfoButton setTitle:[trackInfoCombo userDisplayRep]];
75 trackInfoCombo = [[KeyCombo alloc] init];
78 if ([defaults objectForKey:@"UpcomingSongs"]) {
79 upcomingSongsCombo = [defaults keyComboForKey:@"UpcomingSongs"];
80 [upcomingSongsButton setTitle:[upcomingSongsCombo userDisplayRep]];
82 upcomingSongsCombo = [[KeyCombo alloc] init];
85 //Check current track info buttons
86 [albumCheckbox setState:[defaults boolForKey:@"showAlbum"] ? NSOnState : NSOffState];
87 [nameCheckbox setState:[defaults boolForKey:@"showName"] ? NSOnState : NSOffState];
88 [artistCheckbox setState:[defaults boolForKey:@"showArtist"] ? NSOnState : NSOffState];
89 [trackTimeCheckbox setState:[defaults boolForKey:@"showTime"] ? NSOnState : NSOffState];
91 //Set the launch at login checkbox state
93 NSMutableDictionary *loginwindow;
94 NSMutableArray *loginarray;
97 [defaults synchronize];
98 loginwindow = [[defaults persistentDomainForName:@"loginwindow"] mutableCopy];
99 loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"];
101 for (i = 0; i < [loginarray count]; i++) {
102 NSDictionary *tempDict = [loginarray objectAtIndex:i];
103 if ([[[tempDict objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) {
104 [launchAtLoginCheckbox setState:NSOnState];
110 [window setLevel:NSStatusWindowLevel];
112 [window makeKeyAndOrderFront:nil];
113 [window setDelegate:self];
120 [self setKeyCombo:nil];
121 [playPauseCombo release];
122 [nextTrackCombo release];
123 [prevTrackCombo release];
124 [trackInfoCombo release];
125 [upcomingSongsCombo release];
126 [keyComboPanel release];
127 [menuTableView setDataSource:nil];
128 [allTableView setDataSource:nil];
130 [availableItems release];
131 [submenuItems release];
135 - (IBAction)apply:(id)sender
137 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
138 [defaults setObject:myItems forKey:@"menu"];
141 [defaults setKeyCombo:playPauseCombo forKey:@"PlayPause"];
142 [defaults setKeyCombo:nextTrackCombo forKey:@"NextTrack"];
143 [defaults setKeyCombo:prevTrackCombo forKey:@"PrevTrack"];
144 [defaults setKeyCombo:trackInfoCombo forKey:@"TrackInfo"];
145 [defaults setKeyCombo:upcomingSongsCombo forKey:@"UpcomingSongs"];
147 //Set info checkboxes
148 [defaults setBool:[albumCheckbox state] forKey:@"showAlbum"];
149 [defaults setBool:[nameCheckbox state] forKey:@"showName"];
150 [defaults setBool:[artistCheckbox state] forKey:@"showArtist"];
151 [defaults setBool:[trackTimeCheckbox state] forKey:@"showTime"];
153 //Here we set whether we will launch at login by modifying loginwindow.plist
154 if ([launchAtLoginCheckbox state] == NSOnState) {
155 NSMutableDictionary *loginwindow;
156 NSMutableArray *loginarray;
157 ComponentInstance temp = OpenDefaultComponent(kOSAComponentType, kAppleScriptSubtype);;
161 [defaults synchronize];
162 loginwindow = [[defaults persistentDomainForName:@"loginwindow"] mutableCopy];
163 loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"];
165 for (i = 0; i < [loginarray count]; i++) {
166 NSDictionary *tempDict = [loginarray objectAtIndex:i];
167 if ([[[tempDict objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) {
173 AEDesc scriptDesc, resultDesc;
174 NSString *script = [NSString stringWithFormat:@"tell application \"System Events\"\nmake new login item at end of login items with properties {path:\"%@\", kind:\"APPLICATION\"}\nend tell", [[NSBundle mainBundle] bundlePath]];
176 AECreateDesc(typeChar, [script cString], [script cStringLength],
179 OSADoScript(temp, &scriptDesc, kOSANullScript, typeChar, kOSAModeCanInteract, &resultDesc);
181 AEDisposeDesc(&scriptDesc);
182 AEDisposeDesc(&resultDesc);
183 CloseComponent(temp);
186 NSMutableDictionary *loginwindow;
187 NSMutableArray *loginarray;
190 [[NSUserDefaults standardUserDefaults] synchronize];
191 loginwindow = [[[NSUserDefaults standardUserDefaults] persistentDomainForName:@"loginwindow"] mutableCopy];
192 loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"];
194 for (i = 0; i < [loginarray count]; i++) {
195 NSDictionary *tempDict = [loginarray objectAtIndex:i];
196 if ([[[tempDict objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) {
197 [loginarray removeObjectAtIndex:i];
198 [defaults setPersistentDomain:loginwindow forName:@"loginwindow"];
199 [defaults synchronize];
205 //Set songs in advance
206 if ([songsInAdvance intValue]) {
207 [defaults setInteger:[songsInAdvance intValue] forKey:@"SongsInAdvance"];
209 [defaults setInteger:5 forKey:@"SongsInAdvance"];
213 NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
216 for (i = 0; i < [apps count]; i++) {
217 if ([[[apps objectAtIndex:i] objectForKey:@"NSApplicationName"]
218 isEqualToString:@"iTunes"]) {
226 - (IBAction)cancel:(id)sender
229 [mt closePreferences];
232 - (IBAction)cancelHotKey:(id)sender
234 [[NSNotificationCenter defaultCenter] removeObserver:self];
235 [NSApp endSheet:keyComboPanel];
236 [keyComboPanel orderOut:nil];
239 - (IBAction)clearHotKey:(id)sender
241 [self setKeyCombo:[KeyCombo clearKeyCombo]];
244 - (IBAction)okHotKey:(id)sender
246 NSString *string = [combo userDisplayRep];
251 if ([setHotKey isEqualToString:@"PlayPause"]) {
252 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
253 [combo isEqual:trackInfoCombo] || [combo isEqual:upcomingSongsCombo]) &&
254 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
256 [window setLevel:NSNormalWindowLevel];
257 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
258 [window setLevel:NSStatusWindowLevel];
261 playPauseCombo = [combo copy];
262 [playPauseButton setTitle:string];
264 else if ([setHotKey isEqualToString:@"NextTrack"])
266 if (([combo isEqual:playPauseCombo] || [combo isEqual:prevTrackCombo] ||
267 [combo isEqual:trackInfoCombo] || [combo isEqual:upcomingSongsCombo]) &&
268 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
270 [window setLevel:NSNormalWindowLevel];
271 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
272 [window setLevel:NSStatusWindowLevel];
275 nextTrackCombo = [combo copy];
276 [nextTrackButton setTitle:string];
278 else if ([setHotKey isEqualToString:@"PrevTrack"])
280 if (([combo isEqual:nextTrackCombo] || [combo isEqual:playPauseCombo] ||
281 [combo isEqual:trackInfoCombo] || [combo isEqual:upcomingSongsCombo]) &&
282 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
284 [window setLevel:NSNormalWindowLevel];
285 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
286 [window setLevel:NSStatusWindowLevel];
289 prevTrackCombo = [combo copy];
290 [previousTrackButton setTitle:string];
292 else if ([setHotKey isEqualToString:@"TrackInfo"])
294 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
295 [combo isEqual:playPauseCombo] || [combo isEqual:upcomingSongsCombo]) &&
296 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
298 [window setLevel:NSNormalWindowLevel];
299 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
300 [window setLevel:NSStatusWindowLevel];
303 trackInfoCombo = [combo copy];
304 [trackInfoButton setTitle:string];
306 else if ([setHotKey isEqualToString:@"UpcomingSongs"])
308 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
309 [combo isEqual:trackInfoCombo] || [combo isEqual:playPauseCombo]) &&
310 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
312 [window setLevel:NSNormalWindowLevel];
313 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
314 [window setLevel:NSStatusWindowLevel];
317 upcomingSongsCombo = [combo copy];
318 [upcomingSongsButton setTitle:string];
320 [self cancelHotKey:sender];
323 - (IBAction)save:(id)sender
327 [mt closePreferences];
330 - (IBAction)setCurrentTrackInfo:(id)sender
332 [self setKeyCombo:trackInfoCombo];
333 [self setHotKey:@"TrackInfo"];
336 - (IBAction)setNextTrack:(id)sender
338 [self setKeyCombo:nextTrackCombo];
339 [self setHotKey:@"NextTrack"];
342 - (IBAction)setPlayPause:(id)sender
344 [self setKeyCombo:playPauseCombo];
345 [self setHotKey:@"PlayPause"];
348 - (IBAction)setPreviousTrack:(id)sender
350 [self setKeyCombo:prevTrackCombo];
351 [self setHotKey:@"PrevTrack"];
354 - (IBAction)setUpcomingSongs:(id)sender
356 [self setKeyCombo:upcomingSongsCombo];
357 [self setHotKey:@"UpcomingSongs"];
360 - (void)setHotKey:(NSString *)key
363 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyEvent:) name:@"KeyBroadcasterEvent" object:nil];
364 [NSApp beginSheet:keyComboPanel modalForWindow:window modalDelegate:self didEndSelector:nil contextInfo:nil];
367 - (void)keyEvent:(NSNotification *)note
369 NSDictionary *info = [note userInfo];
374 keyCode = [[info objectForKey:@"KeyCode"] shortValue];
375 modifiers = [[info objectForKey:@"Modifiers"] longValue];
377 newCombo = [[KeyCombo alloc] initWithKeyCode:keyCode andModifiers:modifiers];
378 [self setKeyCombo:newCombo];
381 - (void)setKeyCombo:(KeyCombo *)newCombo
385 combo = [newCombo copy];
387 string = [combo userDisplayRep];
391 [keyComboField setStringValue:string];
397 - (void)windowWillClose:(NSNotification *)note
399 [mt closePreferences];
404 // Table View Datasource Methods
408 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
410 if (aTableView == menuTableView) {
411 return [myItems count];
413 return [availableItems count];
417 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
419 if (aTableView == menuTableView) {
420 if ([[aTableColumn identifier] isEqualToString:@"name"]) {
421 return [myItems objectAtIndex:rowIndex];
423 if ([submenuItems containsObject:[myItems objectAtIndex:rowIndex]])
425 return [NSImage imageNamed:@"submenu"];
431 if ([[aTableColumn identifier] isEqualToString:@"name"]) {
432 return [availableItems objectAtIndex:rowIndex];
434 if ([submenuItems containsObject:[availableItems objectAtIndex:rowIndex]]) {
435 return [NSImage imageNamed:@"submenu"];
443 - (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard
445 if (tableView == menuTableView) {
446 [pboard declareTypes:[NSArray arrayWithObjects:@"MenuTableViewPboardType", nil] owner:self];
447 [pboard setString:[[rows objectAtIndex:0] stringValue] forType:@"MenuTableViewPboardType"];
451 if (tableView == allTableView) {
452 [pboard declareTypes:[NSArray arrayWithObjects:@"AllTableViewPboardType", nil] owner:self];
453 [pboard setString:[[rows objectAtIndex:0] stringValue] forType:@"AllTableViewPboardType"];
459 - (BOOL)tableView:(NSTableView*)tableView acceptDrop:(id <NSDraggingInfo>)info row:(int)row dropOperation:(NSTableViewDropOperation)operation
463 NSString *dragData, *temp;
465 pb = [info draggingPasteboard];
467 if ([[pb types] containsObject:@"MenuTableViewPboardType"]) {
468 dragData = [pb stringForType:@"MenuTableViewPboardType"];
469 dragRow = [dragData intValue];
470 temp = [myItems objectAtIndex:dragRow];
471 [myItems removeObjectAtIndex:dragRow];
473 if (tableView == menuTableView) {
475 [myItems insertObject:temp atIndex:row - 1];
477 [myItems insertObject:temp atIndex:row];
480 if (![temp isEqualToString:@"<separator>"]) {
481 [availableItems addObject:temp];
484 } else if ([[pb types] containsObject:@"AllTableViewPboardType"]) {
485 dragData = [pb stringForType:@"AllTableViewPboardType"];
486 dragRow = [dragData intValue];
487 temp = [availableItems objectAtIndex:dragRow];
489 if (![temp isEqualToString:@"<separator>"]) {
490 [availableItems removeObjectAtIndex:dragRow];
492 [myItems insertObject:temp atIndex:row];
495 [menuTableView reloadData];
496 [allTableView reloadData];
500 - (NSDragOperation)tableView:(NSTableView*)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation
502 if (tableView == allTableView) {
503 if ([[[info draggingPasteboard] types] containsObject:@"AllTableViewPboardType"]) {
504 return NSDragOperationNone;
507 if ([[[info draggingPasteboard] types] containsObject:@"MenuTableViewPboardType"]) {
508 NSString *item = [myItems objectAtIndex:[[[info draggingPasteboard] stringForType:@"MenuTableViewPboardType"] intValue]];
509 if ([item isEqualToString:@"PreferencesÉ"] || [item isEqualToString:@"Quit"]) {
510 return NSDragOperationNone;
514 [tableView setDropRow:-1 dropOperation:NSTableViewDropOn];
515 return NSDragOperationGeneric;
518 if (operation == NSTableViewDropOn || row == -1)
520 return NSDragOperationNone;
523 return NSDragOperationGeneric;