root/trunk/lilypad/Sources/LPPrefsController.m @ 251

Revision 251, 29.3 KB (checked in by jppavao, 5 years ago)

Converted the declarations of "Private" categories to class extensions based on anonymous categories for improved compile-time error checking.

Line 
1//
2//  LPPrefsController.m
3//  Lilypad
4//
5//      Copyright (C) 2006-2008 PT.COM,  All rights reserved.
6//      Authors: Joao Pavao <jpavao@co.sapo.pt>
7//           Jason Kim <jason@512k.org>
8//
9//      For more information on licensing, read the README file.
10//      Para mais informações sobre o licenciamento, leia o ficheiro README.
11//
12
13#import "LPPrefsController.h"
14#import "LPKeychainManager.h"
15#import "LPAccountsController.h"
16#import "LPAccount.h"
17#import "LPAccountPrefsListCell.h"
18#import "LPSapoAgents.h"
19#import "NSString+ConcatAdditions.h"
20#import "LPCommon.h"
21
22
23
24static NSString *AccountUUIDsDraggedType = @"AccountUUIDsDraggedType";
25
26
27@interface LPPrefsController ()  // Private Methods
28
29- (void)p_updateDownloadsFolderMenu;
30
31- (NSSet *)p_allOurURLHandlersBundleIDs;
32- (NSDictionary *)p_infoDictForURLHandlerWithBundleID:(NSString *)bundleID;
33- (NSArray *)p_contentsOfOurURLHandlersMenu;
34- (void)p_updateURLHandlersMenu;
35- (void)p_updateURLHandlersMenuSelection;
36- (void)p_selectedDefaultURLHandler:(id)sender;
37- (void)p_selectOtherURLHandler:(id)sender;
38
39- (LPAccount *)p_selectedAccount;
40- (void)p_startObservingAccounts:(NSArray *)accounts;
41- (void)p_stopObservingAccounts:(NSArray *)accounts;
42
43- (void)p_updateGUIForMSNTransportAgentOfAccount:(LPAccount *)account;
44- (void)p_updateGUIForTransportAgent:(NSString *)transportAgent ofAccount:(LPAccount *)account;
45- (void)p_setButtonEnabled:(NSButton *)btn afterDelay:(float)delay;
46- (void)p_setButtonDisabledAndCancelTimer:(NSButton *)btn;
47@end
48
49
50@implementation LPPrefsController
51
52+ (void)initialize
53{
54        if (self == [LPPrefsController class]) {
55                NSString        *downloadsFolderPath = nil;
56                NSArray         *foundFolders = ((floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_4) ?
57                                                                         nil :
58                                                                         NSSearchPathForDirectoriesInDomains(NSDownloadsDirectory, NSUserDomainMask, YES));
59               
60                if ([foundFolders count] == 0) {
61                        foundFolders = NSSearchPathForDirectoriesInDomains(NSDesktopDirectory, NSUserDomainMask, YES);
62                        if ([foundFolders count] == 0) {
63                                // Build the path manually (last resort)
64                                downloadsFolderPath = [NSHomeDirectory() stringByAppendingPathComponent:@"Desktop"];
65                        }
66                }
67               
68                if (downloadsFolderPath == nil && [foundFolders count] > 0)
69                        downloadsFolderPath = [foundFolders objectAtIndex:0];
70               
71                [[NSUserDefaults standardUserDefaults] registerDefaults:
72                 [NSDictionary dictionaryWithObject:downloadsFolderPath forKey:@"DownloadsFolder"]];
73        }
74}
75
76- (void)dealloc
77{
78        [self p_stopObservingAccounts:[[self accountsController] accounts]];
79        [[self accountsController] removeObserver:self forKeyPath:@"accounts"];
80        [m_accountsController removeObserver:self forKeyPath:@"selectedObjects"];
81       
82        [[NSNotificationCenter defaultCenter] removeObserver:self];
83       
84        [m_generalView release];
85        [m_accountsView release];
86        [m_advancedView release];
87        [m_msnRegistrationSheet release];
88        [m_defaultAccountController release];
89        [m_accountsController release];
90       
91        [super dealloc];
92}
93
94- (void)initializePrefPanes
95{
96        [self addPrefWithView:m_generalView
97                                        label:NSLocalizedString(@"General", @"preference pane label")
98                                        image:[NSImage imageNamed:@"GeneralPrefs"]
99                           identifier:@"GeneralPrefs"];
100       
101        [self addPrefWithView:m_accountsView
102                                        label:NSLocalizedString(@"Accounts", @"preference pane label")
103                                        image:[NSImage imageNamed:@"AccountsPrefs"]
104                           identifier:@"AccountsPrefs"];
105       
106        if ([[NSUserDefaults standardUserDefaults] boolForKey:@"IncludeAdvancedPrefs"]) {
107                [self addAdvancedPrefsPane];
108        }
109}
110
111- (void)addAdvancedPrefsPane
112{
113        [self showPrefs:nil];
114        [self addPrefWithView:m_advancedView
115                                        label:NSLocalizedString(@"Advanced", @"preference pane label")
116                                        image:[NSImage imageNamed:@"AdvancedPrefs"]
117                           identifier:@"AdvancedPrefs"];
118}
119
120- (LPAccountsController *)accountsController
121{
122        return [LPAccountsController sharedAccountsController];
123}
124
125- (void)loadNib
126{
127        [NSBundle loadNibNamed:@"Preferences" owner:self];
128       
129       
130        // General Pane
131        [self p_updateDownloadsFolderMenu];
132        [self p_updateURLHandlersMenu];
133       
134       
135        // Accounts Pane
136        [[self accountsController] addObserver:self
137                                                                forKeyPath:@"accounts"
138                                                                   options:( NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew )
139                                                                   context:NULL];
140        [self p_startObservingAccounts:[[self accountsController] accounts]];
141       
142        [m_accountsController addObserver:self forKeyPath:@"selectedObjects" options:0 context:NULL];
143       
144        [m_accountsTable registerForDraggedTypes:[NSArray arrayWithObject:AccountUUIDsDraggedType]];
145       
146       
147        // Transport Pane
148        LPAccount       *account = [self p_selectedAccount];
149        NSString        *transportAgent = [[account sapoAgents] hostnameForService:@"msn"];
150       
151        [self p_updateGUIForTransportAgent:transportAgent ofAccount:account];
152       
153        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
154        [nc addObserver:self
155                   selector:@selector(accountDidChangeTransportInfo:)
156                           name:LPAccountDidChangeTransportInfoNotification
157                         object:account];
158        [nc addObserver:self
159                   selector:@selector(applicationWillBecomeActive:)
160                           name:NSApplicationWillBecomeActiveNotification
161                         object:NSApp];
162       
163        [m_accountsTable sizeLastColumnToFit];
164}
165
166
167#pragma mark -
168#pragma mark NSWindow Delegate Methods
169
170
171- (void)windowDidBecomeKey:(NSNotification *)aNotification
172{
173        if (m_needsToUpdateURLHandlerMenu) {
174                [self p_updateURLHandlersMenu];
175                m_needsToUpdateURLHandlerMenu = NO;
176        }
177}
178
179- (void)windowDidResignKey:(NSNotification *)aNotification
180{
181        // Try to commit any text field editing session
182        NSWindow *win = [self window];
183        [win makeFirstResponder:win];
184}
185
186- (void)windowWillClose:(NSNotification *)aNotification
187{
188        // The default account controller isn't committing changes automatically upon window close. Maybe it's because the
189        // views with the text fields are not inserted in any windows when the nib is loaded, I don't know. We'll have to
190        // do it manually.
191        [m_defaultAccountController commitEditing];
192        [m_accountsController commitEditing];
193}
194
195
196#pragma mark -
197#pragma mark Actions - General Prefs
198
199
200#pragma mark Downloads Folder
201
202- (void)p_updateDownloadsFolderMenu
203{
204        id                      folderItem = [m_downloadsFolderPopUpButton itemAtIndex:0];
205        NSString        *folderPath = LPDownloadsFolderPath();
206        NSString        *folderDisplayName = [[NSFileManager defaultManager] displayNameAtPath:folderPath];
207        NSImage         *folderImage = [[NSWorkspace sharedWorkspace] iconForFile:folderPath];
208       
209        [folderImage setSize:NSMakeSize(16.0, 16.0)];
210       
211        [folderItem setTitle:folderDisplayName];
212        [folderItem setImage:folderImage];
213}
214
215- (IBAction)chooseDownloadsFolder:(id)sender
216{
217        NSString *downloadsFolder = LPDownloadsFolderPath();
218       
219        NSOpenPanel     *op = [NSOpenPanel openPanel];
220       
221        [op setCanChooseFiles:NO];
222        [op setCanChooseDirectories:YES];
223        [op setCanCreateDirectories:YES];
224
225        [op setResolvesAliases:YES];
226        [op setAllowsMultipleSelection:NO];
227        [op setPrompt:NSLocalizedString(@"Select", @"")];
228       
229        [op beginSheetForDirectory:(downloadsFolder ? downloadsFolder : NSHomeDirectory())
230                                                  file:nil
231                                                 types:nil
232                                modalForWindow:[self window]
233                                 modalDelegate:self
234                                didEndSelector:@selector(p_selectDownloadsFolderPanelDidEnd:returnCode:contextInfo:)
235                                   contextInfo:NULL];
236}
237
238- (void)p_selectDownloadsFolderPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
239{
240        if (returnCode == NSOKButton) {
241                [[NSUserDefaults standardUserDefaults] setObject:[panel filename] forKey:@"DownloadsFolder"];
242                [self p_updateDownloadsFolderMenu];
243        }
244       
245        // Finish by re-selecting the item that references the selected folder (the first one)
246        [m_downloadsFolderPopUpButton selectItemAtIndex:0];
247}
248
249
250- (IBAction)openChatTranscriptsFolder:(id)sender
251{
252        NSString *folderPath = LPChatTranscriptsFolderPath();
253       
254        if (folderPath == nil) {
255                NSBeep();
256        }
257        else {
258                [[NSWorkspace sharedWorkspace] openFile:folderPath];
259        }
260}
261
262
263#pragma mark XMPP/Jabber URL Handler Popup Menu
264
265
266- (NSString *)defaultURLHandlerBundleID
267{
268        // Get the current default handler for our URLs
269        CFStringRef defaultXMPPHandler = LSCopyDefaultHandlerForURLScheme(CFSTR("xmpp"));
270       
271        if (defaultXMPPHandler == NULL)
272                defaultXMPPHandler = LSCopyDefaultHandlerForURLScheme(CFSTR("jabber"));
273       
274        return [(NSString *)defaultXMPPHandler autorelease];
275}
276
277- (void)setDefaultURLHandlerBundleID:(NSString *)bundleID
278{
279        LSSetDefaultHandlerForURLScheme(CFSTR("xmpp"), (CFStringRef)bundleID);
280        LSSetDefaultHandlerForURLScheme(CFSTR("jabber"), (CFStringRef)bundleID);
281       
282        // There's a lot of stuff that may need to be done: we may have to remove the previous handler because it
283        // may not be returned as an app capable of handling our URLs. Or we may need to add a new handler that was
284        // selected using the NSOpenPanel for the "select other" popup menu option.
285        // So, just update the whole menu.
286        [self p_updateURLHandlersMenu];
287}
288
289
290- (NSSet *)p_allOurURLHandlersBundleIDs
291{
292        // Get all the available handlers for our URLs from Launch Services
293        CFArrayRef allXMPPHandlers = LSCopyAllHandlersForURLScheme(CFSTR("xmpp"));
294        CFArrayRef allJabberHandlers = LSCopyAllHandlersForURLScheme(CFSTR("jabber"));
295       
296        // Mix them all together
297        NSMutableSet *allURLHandlers = [NSMutableSet set];
298        [allURLHandlers addObjectsFromArray:(NSArray *)allXMPPHandlers];
299        [allURLHandlers addObjectsFromArray:(NSArray *)allJabberHandlers];
300       
301        CFRelease(allXMPPHandlers);
302        CFRelease(allJabberHandlers);
303       
304        return allURLHandlers;
305}
306
307
308- (NSDictionary *)p_infoDictForURLHandlerWithBundleID:(NSString *)bundleID
309{
310        NSWorkspace             *ws = [NSWorkspace sharedWorkspace];
311        NSString                *appAbsolutePath = [ws absolutePathForAppBundleWithIdentifier:bundleID];
312        NSDictionary    *itemDescription = nil;
313       
314        if (appAbsolutePath) {
315                NSBundle        *appBundle = [NSBundle bundleWithPath:appAbsolutePath];
316               
317                NSString        *appName = [appBundle objectForInfoDictionaryKey:(NSString *)kCFBundleNameKey];
318                NSString        *appVersion = [appBundle objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
319                NSImage         *appIcon = [ws iconForFile:appAbsolutePath];
320               
321                if ([appName length] > 0) {
322                        itemDescription = [NSDictionary dictionaryWithObjectsAndKeys:
323                                bundleID, @"BundleID",
324                                appName, @"AppName",
325                                appVersion, @"Version",
326                                appIcon, @"Icon", nil];
327                }
328        }
329       
330        return itemDescription;
331}
332
333
334- (NSArray *)p_contentsOfOurURLHandlersMenu
335{
336        NSMutableSet *bundleIDsForMenu = [NSMutableSet setWithSet:[self p_allOurURLHandlersBundleIDs]];
337       
338        // Add the default handler to the set of available handlers, in case it isn't in there already.
339        // The user may have chosen an application that isn't registered in the Launch Services database as being
340        // capable of handling this URL scheme.
341        NSString *defaultHandlerBundleID = [self defaultURLHandlerBundleID];
342        if ([defaultHandlerBundleID length] > 0)
343                [bundleIDsForMenu addObject:defaultHandlerBundleID];
344       
345       
346        // Build the actual list sorted by the application names
347        NSMutableArray *URLHandlersMenuContents = [NSMutableArray array];
348       
349        NSEnumerator *handlerBundleIDEnum = [bundleIDsForMenu objectEnumerator];
350        NSString *bundleID;
351        while (bundleID = [handlerBundleIDEnum nextObject]) {
352                NSDictionary *infoDict = [self p_infoDictForURLHandlerWithBundleID:bundleID];
353                if (infoDict)
354                        [URLHandlersMenuContents addObject:infoDict];
355        }
356       
357       
358        NSSortDescriptor *descriptor = [[NSSortDescriptor alloc] initWithKey:@"AppName" ascending:YES
359                                                                                                                                selector:@selector(caseInsensitiveCompare:)];
360        [URLHandlersMenuContents sortUsingDescriptors:[NSArray arrayWithObject:descriptor]];
361        [descriptor release];
362       
363        return URLHandlersMenuContents;
364}
365
366
367- (void)p_updateURLHandlersMenu
368{
369        // Cleanup
370        [m_defaultURLHandlerPopUpButton removeAllItems];
371        [m_defaultURLHandlerPopUpButton setAutoenablesItems:NO];
372       
373        // Add all the applications known to be able to handle our URLs
374        NSEnumerator *handlersEnum = [[self p_contentsOfOurURLHandlersMenu] objectEnumerator];
375        NSDictionary *handlerDescription;
376        while (handlerDescription = [handlersEnum nextObject]) {
377                NSString *menuItemTitle = [NSString stringWithFormat:@"%@ (%@)",
378                        [handlerDescription objectForKey:@"AppName"],
379                        [handlerDescription objectForKey:@"Version"]];
380               
381                [m_defaultURLHandlerPopUpButton addItemWithTitle:menuItemTitle];
382               
383                NSMenuItem *menuItem = [m_defaultURLHandlerPopUpButton lastItem];
384               
385                [[handlerDescription objectForKey:@"Icon"] setSize:NSMakeSize(16.0, 16.0)];
386                [menuItem setImage:[handlerDescription objectForKey:@"Icon"]];
387                [menuItem setRepresentedObject:[handlerDescription objectForKey:@"BundleID"]];
388                [menuItem setTarget:self];
389                [menuItem setAction:@selector(p_selectedDefaultURLHandler:)];
390        }
391       
392        // Add the "Select Other" item
393        [[m_defaultURLHandlerPopUpButton menu] addItem:[NSMenuItem separatorItem]];
394       
395        [m_defaultURLHandlerPopUpButton addItemWithTitle:NSLocalizedString(@"Select Other App...", @"")];
396        NSMenuItem *item = [m_defaultURLHandlerPopUpButton lastItem];
397        [item setTarget:self];
398        [item setAction:@selector(p_selectOtherURLHandler:)];
399       
400        // Select the item for the current default handler
401        [self p_updateURLHandlersMenuSelection];
402}
403
404
405- (void)p_updateURLHandlersMenuSelection
406{
407        NSString *defaultHandlerBundleID = [self defaultURLHandlerBundleID];
408        int indexToSelect = ( [defaultHandlerBundleID length] > 0 ?
409                                                  [m_defaultURLHandlerPopUpButton indexOfItemWithRepresentedObject:defaultHandlerBundleID] :
410                                                  (-1) );
411       
412        // If there's no default item or if it isn't in the menu, then add a "none selected" item at the top
413        if (indexToSelect < 0) {
414                [m_defaultURLHandlerPopUpButton insertItemWithTitle:NSLocalizedString(@"<none selected>", @"") atIndex:0];
415                NSMenuItem *item = [m_defaultURLHandlerPopUpButton itemAtIndex:0];
416                [item setEnabled:NO];
417               
418                [[m_defaultURLHandlerPopUpButton menu] insertItem:[NSMenuItem separatorItem] atIndex:1];
419               
420                indexToSelect = 0;
421        }
422        [m_defaultURLHandlerPopUpButton selectItemAtIndex: indexToSelect];
423}
424
425
426- (void)p_selectedDefaultURLHandler:(id)sender
427{
428        // "sender" should be the selected menu item in the popup menu
429        [self setDefaultURLHandlerBundleID:[sender representedObject]];
430}
431
432
433- (void)p_selectOtherURLHandler:(id)sender
434{
435        NSOpenPanel     *op = [NSOpenPanel openPanel];
436       
437        [op setCanChooseDirectories:NO];
438        [op setCanCreateDirectories:NO];
439        [op setResolvesAliases:YES];
440        [op setAllowsMultipleSelection:NO];
441       
442        [op setPrompt:NSLocalizedString(@"Select", @"")];
443       
444        NSArray *applicationsDirPaths = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSSystemDomainMask, NO);
445        NSString *applicationsDirPath = ( [applicationsDirPaths count] > 0 ?
446                                                                          [applicationsDirPaths objectAtIndex:0] :
447                                                                          @"/Applications" );
448       
449        [op beginSheetForDirectory:applicationsDirPath
450                                                  file:nil
451                                                 types:[NSArray arrayWithObject:@"app"]
452                                modalForWindow:[self window]
453                                 modalDelegate:self
454                                didEndSelector:@selector(p_selectOtherURLHandlerPanelDidEnd:returnCode:contextInfo:)
455                                   contextInfo:NULL];
456}
457
458- (void)p_selectOtherURLHandlerPanelDidEnd:(NSOpenPanel *)panel returnCode:(int)returnCode contextInfo:(void *)contextInfo
459{
460        if (returnCode == NSOKButton) {
461                NSBundle *appBundle = [NSBundle bundleWithPath:[panel filename]];
462                NSString *bundleID = [appBundle bundleIdentifier];
463               
464                if ([bundleID length] > 0) {
465                        [self setDefaultURLHandlerBundleID:bundleID];
466                }
467        }
468       
469        // Finish by selecting the currently default handler so that the "select other" menu item never gets selected
470        [self p_updateURLHandlersMenuSelection];
471}
472
473
474#pragma mark Notifications
475
476
477- (void)applicationWillBecomeActive:(NSNotification *)notif
478{
479        // Just in case the list of URL handlers or the default URL handler changed while we were in the background
480        m_needsToUpdateURLHandlerMenu = YES;
481}
482
483
484#pragma mark -
485#pragma mark Actions - Accounts Prefs
486
487
488- (LPAccount *)p_selectedAccount
489{
490        id selectedObjects = [m_accountsController selectedObjects];
491        return ([selectedObjects count] > 0 ? [selectedObjects objectAtIndex:0] : nil);
492}
493
494- (void)p_startObservingAccounts:(NSArray *)accounts
495{
496        NSEnumerator *accountEnum = [accounts objectEnumerator];
497        LPAccount *account;
498        while (account = [accountEnum nextObject]) {
499                [account addObserver:self forKeyPath:@"enabled" options:0 context:NULL];
500                [account addObserver:self forKeyPath:@"status" options:0 context:NULL];
501                [account addObserver:self forKeyPath:@"description" options:0 context:NULL];
502                [account addObserver:self forKeyPath:@"automaticReconnectionStatus" options:0 context:NULL];
503        }
504}
505
506- (void)p_stopObservingAccounts:(NSArray *)accounts
507{
508        NSEnumerator *accountEnum = [accounts objectEnumerator];
509        LPAccount *account;
510        while (account = [accountEnum nextObject]) {
511                [account removeObserver:self forKeyPath:@"enabled"];
512                [account removeObserver:self forKeyPath:@"status"];
513                [account removeObserver:self forKeyPath:@"description"];
514                [account removeObserver:self forKeyPath:@"automaticReconnectionStatus"];
515        }
516}
517
518- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
519{
520        if ([keyPath isEqualToString:@"accounts"]) {
521                NSKeyValueChange changeKind = [[change valueForKey:NSKeyValueChangeKindKey] intValue];
522               
523                if (changeKind == NSKeyValueChangeInsertion) {
524                        [self p_startObservingAccounts:[change objectForKey:NSKeyValueChangeNewKey]];
525                }
526                else if (changeKind == NSKeyValueChangeRemoval) {
527                        [self p_stopObservingAccounts:[change objectForKey:NSKeyValueChangeOldKey]];
528                }
529                [m_accountsTable setNeedsDisplay:YES];
530        }
531        else if ([keyPath isEqualToString:@"selectedObjects"]) {
532                [self p_updateGUIForMSNTransportAgentOfAccount:[self p_selectedAccount]];
533        }
534        else if ([keyPath isEqualToString:@"enabled"] ||
535                         [keyPath isEqualToString:@"status"] ||
536                         [keyPath isEqualToString:@"description"] ||
537                         [keyPath isEqualToString:@"automaticReconnectionStatus"]) {
538                [m_accountsTable setNeedsDisplay:YES];
539        }
540}
541
542- (IBAction)addAccount:(id)sender
543{
544        [[self accountsController] addNewAccount];
545}
546
547
548- (IBAction)removeAccount:(id)sender
549{
550        NSArray *selectedAccounts = [m_accountsController selectedObjects];
551        NSString *alertTitle = nil;
552        NSString *alertInfo = nil;
553       
554        if ([selectedAccounts count] == 0) {
555                NSBeep();
556        }
557        else {
558                if ([selectedAccounts count] > 1) {
559                        alertTitle = NSLocalizedString(@"Delete the selected accounts?", @"");
560                       
561                        alertInfo = [NSString stringWithFormat:
562                                                 NSLocalizedString(@"This will delete the accounts %@. You can't undo this action.", @""),
563                                                 [NSString concatenatedStringWithValuesForKey:@"description" ofObjects:selectedAccounts
564                                                                                                          useDoubleQuotes:YES maxNrListedItems:5]];
565                }
566                else {
567                        alertTitle = [NSString stringWithFormat:NSLocalizedString(@"Delete the account \"%@\"?", @""),
568                                                  [[selectedAccounts objectAtIndex:0] description]];
569                        alertInfo = NSLocalizedString(@"You can't undo this action.", @"");
570                }
571               
572                NSAlert *alert = [[NSAlert alloc] init];
573               
574                [alert setMessageText:alertTitle];
575                [alert setInformativeText:alertInfo];
576                [alert addButtonWithTitle:NSLocalizedString(@"Delete", @"")];
577                [alert addButtonWithTitle:NSLocalizedString(@"Cancel", @"")];
578               
579                [alert beginSheetModalForWindow:[self window]
580                                                  modalDelegate:self
581                                                 didEndSelector:@selector(p_removeAccountAlertDidEnd:returnCode:contextInfo:)
582                                                        contextInfo:(void *)[selectedAccounts retain]];
583        }
584}
585
586- (void)p_removeAccountAlertDidEnd:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo
587{
588        NSArray *selectedAccounts = [(NSArray *)contextInfo autorelease];
589       
590        if (returnCode == NSAlertFirstButtonReturn) {
591                NSEnumerator *accountsEnum = [selectedAccounts objectEnumerator];
592                LPAccount *account;
593                LPAccountsController *ctrl = [self accountsController];
594               
595                while (account = [accountsEnum nextObject])
596                        [ctrl removeAccount:account];
597        }
598       
599        [alert autorelease];
600}
601
602
603#pragma mark Accounts NSTableView Data Source & Delegate
604
605
606- (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView
607{
608        return 0;
609}
610
611
612- (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex
613{
614        return nil;
615}
616
617
618- (BOOL)tableView:(NSTableView *)aTableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard
619{
620        if ([rowIndexes count] > 1) {
621                return NO;
622        }
623        else {
624                [pboard declareTypes:[NSArray arrayWithObject:AccountUUIDsDraggedType] owner:nil];
625               
626                NSArray *accounts = [[self accountsController] accounts];
627                NSArray *draggedUUIDs = [[accounts objectsAtIndexes:rowIndexes] valueForKey:@"UUID"];
628               
629                [pboard setPropertyList:draggedUUIDs forType:AccountUUIDsDraggedType];
630               
631                return YES;
632        }
633}
634
635
636- (NSDragOperation)tableView:(NSTableView *)aTableView validateDrop:(id <NSDraggingInfo>)info proposedRow:(int)row proposedDropOperation:(NSTableViewDropOperation)operation
637{
638        NSPasteboard *pboard = [info draggingPasteboard];
639       
640        if ([[pboard types] containsObject:AccountUUIDsDraggedType]) {
641               
642                if (operation == NSTableViewDropOn) {
643                        [aTableView setDropRow:row dropOperation:NSTableViewDropAbove];
644                }
645               
646                return NSDragOperationGeneric;
647        }
648        else {
649                return NSDragOperationNone;
650        }
651}
652
653
654- (BOOL)tableView:(NSTableView *)aTableView acceptDrop:(id <NSDraggingInfo>)info row:(int)row dropOperation:(NSTableViewDropOperation)operation
655{
656        BOOL dropWasAccepted = NO;
657       
658        NSPasteboard *pboard = [info draggingPasteboard];
659       
660        if ([[pboard types] containsObject:AccountUUIDsDraggedType]) {
661                NSArray *draggedUUIDs = [pboard propertyListForType:AccountUUIDsDraggedType];
662               
663                NSAssert(([draggedUUIDs count] == 1), @"[draggedUUIDs count] != 1");
664               
665                NSString *draggedAccountUUID = [draggedUUIDs objectAtIndex:0];
666                LPAccount *draggedAccount = [[self accountsController] accountForUUID:draggedAccountUUID];
667               
668                LPAccountsController *accountsController = [self accountsController];
669                int draggedAccountCurrentIndex = [[accountsController accounts] indexOfObject:draggedAccount];
670               
671                int targetIndex = (row > draggedAccountCurrentIndex ? row - 1 : row);
672                if (targetIndex != draggedAccountCurrentIndex) {
673                        // Move it!
674                        [accountsController moveAccount:draggedAccount toIndex:targetIndex];
675                        dropWasAccepted = YES;
676                }
677        }
678       
679        return dropWasAccepted;
680}
681
682
683#pragma mark -
684#pragma mark Actions - MSN Account Prefs - Private
685
686
687- (void)p_enableButton:(NSButton *)btn
688{
689        [btn setEnabled:YES];
690}
691
692- (void)p_setButtonEnabled:(NSButton *)btn afterDelay:(float)delay
693{
694        [btn setEnabled:NO];
695        [self performSelector:@selector(p_enableButton:) withObject:btn afterDelay:delay];
696}
697
698- (void)p_setButtonDisabledAndCancelTimer:(NSButton *)btn
699{
700        [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(p_enableButton:) object:btn];
701        [btn setEnabled:NO];
702}
703
704
705- (void)p_updateGUIForMSNTransportAgentOfAccount:(LPAccount *)account
706{
707        [self p_updateGUIForTransportAgent:[[account sapoAgents] hostnameForService:@"msn"] ofAccount:account];
708}
709
710
711- (void)p_updateGUIForTransportAgent:(NSString *)transportAgent ofAccount:(LPAccount *)account
712{
713        if (account == [self p_selectedAccount]) {
714                BOOL            isRegistered = [account isRegisteredWithTransportAgent:transportAgent];
715                NSString        *registeredUsername = [account usernameRegisteredWithTransportAgent:transportAgent];
716                BOOL            isLoggedIn = [account isLoggedInWithTransportAgent:transportAgent];
717               
718                if ([account isOffline]) {
719                        [m_msnTransportStatusView setStringValue:
720                         NSLocalizedString(@"The current MSN state is unknown.",
721                                                           @"MSN transport state description")];
722                       
723                        [m_msnRegistrationButton setTitle:NSLocalizedString(@"Register...", @"MSN transport preferences button")];
724                        [m_msnRegistrationButton setEnabled:NO];
725                       
726                        [m_msnLoginButton setTitle:NSLocalizedString(@"Log In", @"MSN transport preferences button")];
727                        [self p_setButtonDisabledAndCancelTimer:m_msnLoginButton];
728                }
729                else {
730                        if (!isRegistered) {
731                                [m_msnTransportStatusView setStringValue:
732                                 NSLocalizedString(@"You're not currently registered to the MSN transport.",
733                                                                   @"MSN transport state description")];
734                               
735                                [m_msnRegistrationButton setTitle:NSLocalizedString(@"Register...", @"MSN transport preferences button")];
736                                [m_msnRegistrationButton setEnabled:YES];
737                               
738                                [m_msnLoginButton setTitle:NSLocalizedString(@"Log In", @"MSN transport preferences button")];
739                                [self p_setButtonDisabledAndCancelTimer:m_msnLoginButton];
740                        }
741                        else if (!isLoggedIn) {
742                                [m_msnTransportStatusView setStringValue:
743                                 [NSString stringWithFormat:
744                                  NSLocalizedString(@"You're currently registered to the MSN transport with the email \"%@\", but you're not logged in to the service.",
745                                                                        @"MSN transport state description"),
746                                  registeredUsername]];
747                               
748                                [m_msnRegistrationButton setTitle:NSLocalizedString(@"Unregister...", @"MSN transport preferences button")];
749                                [m_msnRegistrationButton setEnabled:YES];
750                               
751                                [m_msnLoginButton setTitle:NSLocalizedString(@"Log In", @"MSN transport preferences button")];
752                                [self p_setButtonEnabled:m_msnLoginButton afterDelay:0.0];
753                        }
754                        else {
755                                [m_msnTransportStatusView setStringValue:
756                                 [NSString stringWithFormat:
757                                  NSLocalizedString(@"You're currently registered to the MSN transport with the email \"%@\" and you're logged in to the service.",
758                                                                        @"MSN transport state description"),
759                                  registeredUsername]];
760                               
761                                [m_msnRegistrationButton setTitle:NSLocalizedString(@"Unregister...", @"MSN transport preferences button")];
762                                [m_msnRegistrationButton setEnabled:YES];
763                               
764                                [m_msnLoginButton setTitle:NSLocalizedString(@"Log In", @"MSN transport preferences button")];
765                                [self p_setButtonDisabledAndCancelTimer:m_msnLoginButton];
766                        }
767                }
768        }
769}
770
771
772#pragma mark Actions - MSN Account Prefs - Public
773
774
775- (IBAction)registerMSNTransport:(id)sender
776{
777        LPAccount       *account = [self p_selectedAccount];
778        NSString        *transportAgent = [[account sapoAgents] hostnameForService:@"msn"];
779       
780        BOOL            isRegistered = [account isRegisteredWithTransportAgent:transportAgent];
781       
782        if ([account isOnline]) {
783                if (!isRegistered) {
784                        // Register
785                        NSString *lastRegisteredEmail = [account lastRegisteredMSNEmail];
786                        NSString *lastRegisteredPassword = [account lastRegisteredMSNPassword];
787                       
788                        [m_msnEmailField setStringValue:(lastRegisteredEmail ? lastRegisteredEmail : @"")];
789                        [m_msnPasswordField setStringValue:(lastRegisteredPassword ? lastRegisteredPassword : @"")];
790                       
791                        [NSApp beginSheet:m_msnRegistrationSheet
792                           modalForWindow:[self window]
793                                modalDelegate:self
794                           didEndSelector:@selector(p_msnRegistrationSheetDidEnd:returnCode:contextInfo:)
795                                  contextInfo:NULL];
796                }
797                else {
798                        // Unregister
799                        NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Are you sure you want to unregister from the MSN transport?", @"Alert displayed when unregistering from the MSN transport")
800                                                                                         defaultButton:NSLocalizedString(@"OK", @"")
801                                                                                   alternateButton:NSLocalizedString(@"Cancel", @"")
802                                                                                           otherButton:nil
803                                                                 informativeTextWithFormat:NSLocalizedString(@"All your MSN contacts will be removed from the SAPO Messenger buddy list when you unregister from the MSN transport. If you moved contacts to different groups, these changes will be lost. You can't undo this action.", @"Alert displayed when unregistering from the MSN transport")];
804                       
805                        [alert beginSheetModalForWindow:[self window]
806                                                          modalDelegate:self
807                                                         didEndSelector:@selector(p_msnUnregistrationAlertDidEnd:returnCode:contextInfo:)
808                                                                contextInfo:NULL];
809                }
810        }
811}
812
813
814- (void)p_msnRegistrationSheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
815{
816        [sheet orderOut:self];
817       
818        if (returnCode == NSOKButton) {
819                LPAccount       *account = [self p_selectedAccount];
820                NSString        *transportAgent = [[account sapoAgents] hostnameForService:@"msn"];
821               
822                if ([account isOnline]) {
823                        [account registerWithTransportAgent:transportAgent
824                                                                           username:[m_msnEmailField stringValue]
825                                                                           password:[m_msnPasswordField stringValue]];
826                }
827        }
828}
829
830
831- (void)p_msnUnregistrationAlertDidEnd:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(void *)contextInfo
832{
833        if (returnCode == NSAlertDefaultReturn) {
834                LPAccount       *account = [self p_selectedAccount];
835                NSString        *transportAgent = [[account sapoAgents] hostnameForService:@"msn"];
836               
837                if ([account isOnline]) {
838                        [account unregisterWithTransportAgent:transportAgent];
839                }
840        }
841}
842
843
844- (IBAction)loginToMSNTransport:(id)sender
845{
846        [self p_setButtonDisabledAndCancelTimer:m_msnLoginButton];
847        [self p_setButtonEnabled:m_msnLoginButton afterDelay:10.0];
848       
849        // Send a dummy presence so that the MSN transport can connect
850        LPAccount *account = [self p_selectedAccount];
851        [account setTargetStatus:[account status]];
852}
853
854
855#pragma mark MSN Registration Sheet
856
857
858- (IBAction)okRegisterMSN:(id)sender
859{
860        [NSApp endSheet:m_msnRegistrationSheet returnCode:NSOKButton];
861}
862
863
864- (IBAction)cancelRegisterMSN:(id)sender
865{
866        [NSApp endSheet:m_msnRegistrationSheet returnCode:NSCancelButton];
867}
868
869
870- (void)controlTextDidChange:(NSNotification *)aNotification
871{
872        [m_msnRegisterOKButton setEnabled:( ( [[m_msnEmailField stringValue] length] > 0 ) &&
873                                                                                ( [[m_msnPasswordField stringValue] length] > 0 ) )];
874}
875
876
877#pragma mark -
878#pragma mark Actions - Advanced Prefs
879
880
881- (NSArray *)appcastFeeds
882{
883        return [NSArray arrayWithObjects:
884                [NSDictionary dictionaryWithObjectsAndKeys:
885                        NSLocalizedString(@"Stable Releases", @"auto-update feed selection"),
886                        @"Label",
887                        @"http://messenger.sapo.pt/software_update/mac/feeds/sapomsgmac_stable.xml",
888                        @"AutoupdateURL",
889                        nil],
890                [NSDictionary dictionaryWithObjectsAndKeys:
891                        NSLocalizedString(@"Beta Releases", @"auto-update feed selection"),
892                        @"Label",
893                        @"http://messenger.sapo.pt/software_update/mac/feeds/sapomsgmac_beta.xml",
894                        @"AutoupdateURL",
895                        nil],
896                [NSDictionary dictionaryWithObjectsAndKeys:
897                        NSLocalizedString(@"Nightly Builds", @"auto-update feed selection"),
898                        @"Label",
899                        @"http://messenger.sapo.pt/software_update/mac/nightly_builds/appcast_feed.xml",
900                        @"AutoupdateURL",
901                        nil],
902                nil];
903}
904
905
906#pragma mark -
907#pragma mark Account Notifications
908
909
910- (void)accountDidChangeTransportInfo:(NSNotification *)notif
911{
912        NSString *transportAgent = [[notif userInfo] objectForKey:@"TransportAgent"];
913        [self p_updateGUIForTransportAgent:transportAgent ofAccount:[notif object]];
914}
915
916
917@end
Note: See TracBrowser for help on using the browser.