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];
18 [NSBundle loadNibNamed:@"Preferences" owner:self];
20 //Set the table view cells up
21 [imgCell setImageScaling:NSScaleNone];
22 [[menuTableView tableColumnWithIdentifier:@"submenu"] setDataCell:imgCell];
23 [[allTableView tableColumnWithIdentifier:@"submenu"] setDataCell:imgCell];
25 //Register for drag and drop
26 [menuTableView registerForDraggedTypes:[NSArray arrayWithObjects:@"MenuTableViewPboardType", @"AllTableViewPboardType", nil]];
27 [allTableView registerForDraggedTypes:[NSArray arrayWithObjects:@"MenuTableViewPboardType", @"AllTableViewPboardType", nil]];
29 //Set the list of items you can have.
30 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];
32 //Get our preferred menu
33 myItems = [[[NSUserDefaults standardUserDefaults] arrayForKey:@"menu"] mutableCopy];
35 //Delete items in the availableItems array that are already part of the menu
36 for (i = 0; i < [myItems count]; i++) {
37 NSString *item = [myItems objectAtIndex:i];
38 if (![item isEqualToString:@"<separator>"])
40 [availableItems removeObject:item];
44 //Items that show should a submenu image
45 submenuItems = [[NSArray alloc] initWithObjects:@"Upcoming Songs", @"Playlists", @"EQ Presets", @"Song Rating", nil];
47 //Fill in the number of songs in advance to show field
48 [songsInAdvance setIntValue:[defaults integerForKey:@"SongsInAdvance"]];
50 //Fill in hot key buttons
51 if ([defaults objectForKey:@"PlayPause"]){
52 playPauseCombo = [defaults keyComboForKey:@"PlayPause"];
53 [playPauseButton setTitle:[playPauseCombo userDisplayRep]];
55 playPauseCombo = [[KeyCombo alloc] init];
58 if ([defaults objectForKey:@"NextTrack"]) {
59 nextTrackCombo = [defaults keyComboForKey:@"NextTrack"];
60 [nextTrackButton setTitle:[nextTrackCombo userDisplayRep]];
62 nextTrackCombo = [[KeyCombo alloc] init];
65 if ([defaults objectForKey:@"PrevTrack"]) {
66 prevTrackCombo = [defaults keyComboForKey:@"PrevTrack"];
67 [previousTrackButton setTitle:[prevTrackCombo userDisplayRep]];
69 prevTrackCombo = [[KeyCombo alloc] init];
72 if ([defaults objectForKey:@"TrackInfo"]) {
73 trackInfoCombo = [defaults keyComboForKey:@"TrackInfo"];
74 [trackInfoButton setTitle:[trackInfoCombo userDisplayRep]];
76 trackInfoCombo = [[KeyCombo alloc] init];
79 if ([defaults objectForKey:@"UpcomingSongs"]) {
80 upcomingSongsCombo = [defaults keyComboForKey:@"UpcomingSongs"];
81 [upcomingSongsButton setTitle:[upcomingSongsCombo userDisplayRep]];
83 upcomingSongsCombo = [[KeyCombo alloc] init];
86 //Check current track info buttons
87 [albumCheckbox setState:[defaults boolForKey:@"showAlbum"] ? NSOnState : NSOffState];
88 [nameCheckbox setState:[defaults boolForKey:@"showName"] ? NSOnState : NSOffState];
89 [artistCheckbox setState:[defaults boolForKey:@"showArtist"] ? NSOnState : NSOffState];
90 [trackTimeCheckbox setState:[defaults boolForKey:@"showTime"] ? NSOnState : NSOffState];
92 //Set the launch at login checkbox state
94 NSMutableDictionary *loginwindow;
95 NSMutableArray *loginarray;
98 [defaults synchronize];
99 loginwindow = [[defaults persistentDomainForName:@"loginwindow"] mutableCopy];
100 loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"];
102 for (i = 0; i < [loginarray count]; i++) {
103 NSDictionary *tempDict = [loginarray objectAtIndex:i];
104 if ([[[tempDict objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) {
105 [launchAtLoginCheckbox setState:NSOnState];
111 [window setLevel:NSStatusWindowLevel];
113 [window makeKeyAndOrderFront:nil];
114 [window setDelegate:self];
121 [self setKeyCombo:nil];
122 [playPauseCombo release];
123 [nextTrackCombo release];
124 [prevTrackCombo release];
125 [trackInfoCombo release];
126 [upcomingSongsCombo release];
127 [keyComboPanel release];
128 [menuTableView setDataSource:nil];
129 [allTableView setDataSource:nil];
131 [availableItems release];
132 [submenuItems release];
136 - (IBAction)apply:(id)sender
138 NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
139 [defaults setObject:myItems forKey:@"menu"];
142 [defaults setKeyCombo:playPauseCombo forKey:@"PlayPause"];
143 [defaults setKeyCombo:nextTrackCombo forKey:@"NextTrack"];
144 [defaults setKeyCombo:prevTrackCombo forKey:@"PrevTrack"];
145 [defaults setKeyCombo:trackInfoCombo forKey:@"TrackInfo"];
146 [defaults setKeyCombo:upcomingSongsCombo forKey:@"UpcomingSongs"];
148 //Set info checkboxes
149 [defaults setBool:[albumCheckbox state] forKey:@"showAlbum"];
150 [defaults setBool:[nameCheckbox state] forKey:@"showName"];
151 [defaults setBool:[artistCheckbox state] forKey:@"showArtist"];
152 [defaults setBool:[trackTimeCheckbox state] forKey:@"showTime"];
154 //Here we set whether we will launch at login by modifying loginwindow.plist
155 if ([launchAtLoginCheckbox state] == NSOnState) {
156 NSMutableDictionary *loginwindow;
157 NSMutableArray *loginarray;
158 ComponentInstance temp = OpenDefaultComponent(kOSAComponentType, kAppleScriptSubtype);;
162 [defaults synchronize];
163 loginwindow = [[defaults persistentDomainForName:@"loginwindow"] mutableCopy];
164 loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"];
166 for (i = 0; i < [loginarray count]; i++) {
167 NSDictionary *tempDict = [loginarray objectAtIndex:i];
168 if ([[[tempDict objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) {
174 AEDesc scriptDesc, resultDesc;
175 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]];
177 AECreateDesc(typeChar, [script cString], [script cStringLength],
180 OSADoScript(temp, &scriptDesc, kOSANullScript, typeChar, kOSAModeCanInteract, &resultDesc);
182 AEDisposeDesc(&scriptDesc);
183 AEDisposeDesc(&resultDesc);
184 CloseComponent(temp);
187 NSMutableDictionary *loginwindow;
188 NSMutableArray *loginarray;
191 [[NSUserDefaults standardUserDefaults] synchronize];
192 loginwindow = [[[NSUserDefaults standardUserDefaults] persistentDomainForName:@"loginwindow"] mutableCopy];
193 loginarray = [loginwindow objectForKey:@"AutoLaunchedApplicationDictionary"];
195 for (i = 0; i < [loginarray count]; i++) {
196 NSDictionary *tempDict = [loginarray objectAtIndex:i];
197 if ([[[tempDict objectForKey:@"Path"] lastPathComponent] isEqualToString:[[[NSBundle mainBundle] bundlePath] lastPathComponent]]) {
198 [loginarray removeObjectAtIndex:i];
199 [defaults setPersistentDomain:loginwindow forName:@"loginwindow"];
200 [defaults synchronize];
206 //Set songs in advance
207 if ([songsInAdvance intValue]) {
208 [defaults setInteger:[songsInAdvance intValue] forKey:@"SongsInAdvance"];
210 [defaults setInteger:5 forKey:@"SongsInAdvance"];
214 NSArray *apps = [[NSWorkspace sharedWorkspace] launchedApplications];
217 for (i = 0; i < [apps count]; i++) {
218 if ([[[apps objectAtIndex:i] objectForKey:@"NSApplicationName"]
219 isEqualToString:@"iTunes"]) {
227 - (IBAction)cancel:(id)sender
230 [mt closePreferences];
233 - (IBAction)cancelHotKey:(id)sender
235 [[NSNotificationCenter defaultCenter] removeObserver:self];
236 [NSApp endSheet:keyComboPanel];
237 [keyComboPanel orderOut:nil];
240 - (IBAction)clearHotKey:(id)sender
242 [self setKeyCombo:[KeyCombo clearKeyCombo]];
245 - (IBAction)okHotKey:(id)sender
247 NSString *string = [combo userDisplayRep];
252 if ([setHotKey isEqualToString:@"PlayPause"]) {
253 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
254 [combo isEqual:trackInfoCombo] || [combo isEqual:upcomingSongsCombo]) &&
255 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
257 [window setLevel:NSNormalWindowLevel];
258 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
259 [window setLevel:NSStatusWindowLevel];
262 playPauseCombo = [combo copy];
263 [playPauseButton setTitle:string];
265 else if ([setHotKey isEqualToString:@"NextTrack"])
267 if (([combo isEqual:playPauseCombo] || [combo isEqual:prevTrackCombo] ||
268 [combo isEqual:trackInfoCombo] || [combo isEqual:upcomingSongsCombo]) &&
269 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
271 [window setLevel:NSNormalWindowLevel];
272 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
273 [window setLevel:NSStatusWindowLevel];
276 nextTrackCombo = [combo copy];
277 [nextTrackButton setTitle:string];
279 else if ([setHotKey isEqualToString:@"PrevTrack"])
281 if (([combo isEqual:nextTrackCombo] || [combo isEqual:playPauseCombo] ||
282 [combo isEqual:trackInfoCombo] || [combo isEqual:upcomingSongsCombo]) &&
283 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
285 [window setLevel:NSNormalWindowLevel];
286 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
287 [window setLevel:NSStatusWindowLevel];
290 prevTrackCombo = [combo copy];
291 [previousTrackButton setTitle:string];
293 else if ([setHotKey isEqualToString:@"TrackInfo"])
295 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
296 [combo isEqual:playPauseCombo] || [combo isEqual:upcomingSongsCombo]) &&
297 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
299 [window setLevel:NSNormalWindowLevel];
300 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
301 [window setLevel:NSStatusWindowLevel];
304 trackInfoCombo = [combo copy];
305 [trackInfoButton setTitle:string];
307 else if ([setHotKey isEqualToString:@"UpcomingSongs"])
309 if (([combo isEqual:nextTrackCombo] || [combo isEqual:prevTrackCombo] ||
310 [combo isEqual:trackInfoCombo] || [combo isEqual:playPauseCombo]) &&
311 !(([combo modifiers] == -1) && ([combo keyCode] == -1))) {
313 [window setLevel:NSNormalWindowLevel];
314 NSRunAlertPanel(@"Duplicate Key Combo", @"Please choose a unique key combo.", @"OK", nil, nil, nil);
315 [window setLevel:NSStatusWindowLevel];
318 upcomingSongsCombo = [combo copy];
319 [upcomingSongsButton setTitle:string];
321 [self cancelHotKey:sender];
324 - (IBAction)save:(id)sender
328 [mt closePreferences];
331 - (IBAction)setCurrentTrackInfo:(id)sender
333 [self setKeyCombo:trackInfoCombo];
334 [self setHotKey:@"TrackInfo"];
337 - (IBAction)setNextTrack:(id)sender
339 [self setKeyCombo:nextTrackCombo];
340 [self setHotKey:@"NextTrack"];
343 - (IBAction)setPlayPause:(id)sender
345 [self setKeyCombo:playPauseCombo];
346 [self setHotKey:@"PlayPause"];
349 - (IBAction)setPreviousTrack:(id)sender
351 [self setKeyCombo:prevTrackCombo];
352 [self setHotKey:@"PrevTrack"];
355 - (IBAction)setUpcomingSongs:(id)sender
357 [self setKeyCombo:upcomingSongsCombo];
358 [self setHotKey:@"UpcomingSongs"];
361 - (void)setHotKey:(NSString *)key
364 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyEvent:) name:@"KeyBroadcasterEvent" object:nil];
365 [NSApp beginSheet:keyComboPanel modalForWindow:window modalDelegate:self didEndSelector:nil contextInfo:nil];
368 - (void)keyEvent:(NSNotification *)note
370 NSDictionary *info = [note userInfo];
375 keyCode = [[info objectForKey:@"KeyCode"] shortValue];
376 modifiers = [[info objectForKey:@"Modifiers"] longValue];
378 newCombo = [[KeyCombo alloc] initWithKeyCode:keyCode andModifiers:modifiers];
379 [self setKeyCombo:newCombo];
382 - (void)setKeyCombo:(KeyCombo *)newCombo
386 combo = [newCombo copy];
388 string = [combo userDisplayRep];
392 [keyComboField setStringValue:string];
398 - (void)windowWillClose:(NSNotification *)note
400 [mt closePreferences];
405 // Table View Datasource Methods
409 - (int)numberOfRowsInTableView:(NSTableView *)aTableView
411 if (aTableView == menuTableView) {
412 return [myItems count];
414 return [availableItems count];
418 - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex
420 if (aTableView == menuTableView) {
421 if ([[aTableColumn identifier] isEqualToString:@"name"]) {
422 return [myItems objectAtIndex:rowIndex];
424 if ([submenuItems containsObject:[myItems objectAtIndex:rowIndex]])
426 return [NSImage imageNamed:@"submenu"];
432 if ([[aTableColumn identifier] isEqualToString:@"name"]) {
433 return [availableItems objectAtIndex:rowIndex];
435 if ([submenuItems containsObject:[availableItems objectAtIndex:rowIndex]]) {
436 return [NSImage imageNamed:@"submenu"];
444 - (BOOL)tableView:(NSTableView *)tableView writeRows:(NSArray*)rows toPasteboard:(NSPasteboard*)pboard
446 if (tableView == menuTableView) {
447 [pboard declareTypes:[NSArray arrayWithObjects:@"MenuTableViewPboardType", nil] owner:self];
448 [pboard setString:[[rows objectAtIndex:0] stringValue] forType:@"MenuTableViewPboardType"];
452 if (tableView == allTableView) {
453 [pboard declareTypes:[NSArray arrayWithObjects:@"AllTableViewPboardType", nil] owner:self];
454 [pboard setString:[[rows objectAtIndex:0] stringValue] forType:@"AllTableViewPboardType"];
460 - (BOOL)tableView:(NSTableView*)tableView acceptDrop:(id <NSDraggingInfo>)info row:(int)row dropOperation:(NSTableViewDropOperation)operation
464 NSString *dragData, *temp;
466 pb = [info draggingPasteboard];
468 if ([[pb types] containsObject:@"MenuTableViewPboardType"]) {
469 dragData = [pb stringForType:@"MenuTableViewPboardType"];
470 dragRow = [dragData intValue];
471 temp = [myItems objectAtIndex:dragRow];
472 [myItems removeObjectAtIndex:dragRow];
474 if (tableView == menuTableView) {
476 [myItems insertObject:temp atIndex:row - 1];
478 [myItems insertObject:temp atIndex:row];
481 if (![temp isEqualToString:@"<separator>"]) {
482 [availableItems addObject:temp];
485 } else if ([[pb types] containsObject:@"AllTableViewPboardType"]) {
486 dragData = [pb stringForType:@"AllTableViewPboardType"];
487 dragRow = [dragData intValue];
488 temp = [availableItems objectAtIndex:dragRow];
490 if (![temp isEqualToString:@"<separator>"]) {
491 [availableItems removeObjectAtIndex:dragRow];
493 [myItems insertObject:temp atIndex:row];
496 [menuTableView reloadData];
497 [allTableView reloadData];
501 - (NSDragOperation)tableView:(NSTableView*)tableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation
503 if (tableView == allTableView) {
504 if ([[[info draggingPasteboard] types] containsObject:@"AllTableViewPboardType"]) {
505 return NSDragOperationNone;
508 if ([[[info draggingPasteboard] types] containsObject:@"MenuTableViewPboardType"]) {
509 NSString *item = [myItems objectAtIndex:[[[info draggingPasteboard] stringForType:@"MenuTableViewPboardType"] intValue]];
510 if ([item isEqualToString:@"PreferencesÉ"] || [item isEqualToString:@"Quit"]) {
511 return NSDragOperationNone;
515 [tableView setDropRow:-1 dropOperation:NSTableViewDropOn];
516 return NSDragOperationGeneric;
519 if (operation == NSTableViewDropOn || row == -1)
521 return NSDragOperationNone;
524 return NSDragOperationGeneric;