William Bowling is sharing code with you

Bitbucket is a code hosting site. Unlimited public and private repositories. Free for small teams.

Don't show this again

wbowling / adium (fork of adium / adium)

Fork of Adium for patches/improvements

Clone this repository (size: 338.7 MB): HTTPS / SSH
hg clone https://bitbucket.org/wbowling/adium
hg clone ssh://hg@bitbucket.org/wbowling/adium

adium / Source / AdiumSetupWizard.m

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
//
//  AdiumSetupWizard.m
//  Adium
//
//  Created by Evan Schoenberg on 12/4/05.
//

#import "AdiumSetupWizard.h"
#import <Adium/AIAccountControllerProtocol.h>
#import <Adium/AIContentControllerProtocol.h>
#import "SetupWizardBackgroundView.h"
#import "GBFireImporter.h"
#import "BGICImportController.h"
#import <AIUtilities/AIImageAdditions.h>
#import "AIServiceMenu.h"
#import <Adium/AIService.h>
#import <Adium/AIAccount.h>
#import <AIUtilities/AIStringFormatter.h>
#import <AIUtilities/AIFileManagerAdditions.h>
#import "AIHTMLDecoder.h"

#define ACCOUNT_SETUP_IDENTIFIER        @"account_setup"
#define IMPORT_IDENTIFIER                       @"import_client"
#define WELCOME_IDENTIFIER                      @"welcome"
#define DONE_IDENTIFIER                         @"done"

enum{
        WIZARD_TAB_WELCOME = 0,
        WIZARD_TAB_FIREIMPORT = 1,
        WIZARD_TAB_ADD_ACCOUNTS = 2,
        WIZARD_TAB_DONE = 3
};

/*!
 * @class AdiumSetupWizard
 * @brief Class responsible for the first-run setup wizard
 */
@implementation AdiumSetupWizard

/*!
 * @brief Run the wizard
 */
+ (void)runWizard
{
        AdiumSetupWizard *setupWizardWindowController;
        
        setupWizardWindowController = [[self alloc] initWithWindowNibName:@"SetupWizard"];
        
        //Configure and show window
        [setupWizardWindowController showWindow:nil];
        [[setupWizardWindowController window] orderFront:nil];
}

/*!
 * @brief Localized some common items' titles
 */
- (void)localizeItems
{
        [button_goBack setLocalizedString:AILocalizedString(@"Go Back","'go back' button title")];
        [textField_passwordLabel setLocalizedString:AILocalizedString(@"Password:", "Label for the password field in the account preferences")];
        [textField_serviceLabel setLocalizedString:AILocalizedString(@"Service:",nil)];
        
        [button_informationAboutImporting setLocalizedString:AILocalizedString(@"Information About Importing", "button title for more information about importing information in the setup wizard")];
        [button_alternate setLocalizedString:AILocalizedString(@"Skip Import","button title for skipping the import of another client in the setup wizard")];
}

/*!
 * @brief The window loaded
 */
- (void)windowDidLoad
{
        [[self window] setTitle:AILocalizedString(@"Adium Setup Assistant",nil)];

        //Ensure the first tab view item is selected
        [tabView selectTabViewItemAtIndex:WIZARD_TAB_WELCOME];
        [self tabView:tabView willSelectTabViewItem:[tabView selectedTabViewItem]];

        //Configure our background view; it should display the image transparently where our tabView overlaps it
        [backgroundView setBackgroundImage:[NSImage imageNamed:@"AdiumyButler"
                                                                                                  forClass:[self class]]];
        NSRect tabViewFrame = [tabView frame];
        NSRect backgroundViewFrame = [backgroundView frame];
        tabViewFrame.origin.x -= backgroundViewFrame.origin.x;
        tabViewFrame.origin.y -= backgroundViewFrame.origin.y;
        [backgroundView setTransparentRect:tabViewFrame];

        //Check to see if we can import Fire's settings
        NSFileManager *fileManager = [NSFileManager defaultManager];
        NSString *fireDir = [[fileManager userApplicationSupportFolder] stringByAppendingPathComponent:@"Fire"];
        BOOL isDir = NO;
        if([fileManager fileExistsAtPath:fireDir isDirectory:&isDir] && isDir)
                canImport = YES;
        if([progress_processing respondsToSelector:@selector(setHidden:)])
                [progress_processing setHidden:YES];
        
        [self localizeItems];
        
        [[self window] center];

        [super windowDidLoad];
}

- (IBAction)promptForMultiples:(id)sender
{
        // Since we have multiple dedicated importers in 1.1+ it's better to direct the user as needed
        NSAlert *multipleImportPrompt = [NSAlert alertWithMessageText:AILocalizedString(@"Have you used other chat clients?", "Title which introduces import assistants during setup")
                                                                                                        defaultButton:AILocalizedStringFromTable(@"Continue", @"Buttons", nil)
                                                                                                  alternateButton:AILocalizedString(@"Import from Fire", "Fire is another OS X instant messaging client; the name probably should not be localized")
                                                                                                          otherButton:AILocalizedString(@"Import from iChat", "iChat is the OS X instant messaging client which ships with OS X; the name probably should not be localized")
                                                                                informativeTextWithFormat:AILocalizedString(@"Adium includes assistants to import your accounts, settings, and transcripts from other clients. Choose a client below to open its assistant, or press Continue to skip importing.", nil)];
        [multipleImportPrompt beginSheetModalForWindow:[self window] 
                                                                         modalDelegate:self 
                                                                        didEndSelector:@selector(multipleImportAlertDidEnd:returnCode:contextInfo:) 
                                                                           contextInfo:nil];    
}

- (void)multipleImportAlertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
        if(returnCode == NSAlertOtherReturn)
        {
                [BGICImportController performSelector:@selector(importIChatConfiguration)
                                                                   withObject:nil
                                                                   afterDelay:0.5];
                [[self window] close];
        }
        if(returnCode == NSAlertAlternateReturn)
        {
                // not yet supported, but should open the manual Fire importer
        }
}

/*!
 * @brief Perform behaviors before the window closes
 *
 * As our window is closing, we auto-release this window controller instance.
 */
- (void)windowWillClose:(id)sender
{
        [super windowWillClose:sender];
        
        [self autorelease];
}

/*!
 * @brief Start the progress indicator to let the user we are processing
 */
- (void)activateProgressIndicator
{
        [progress_processing setHidden:NO];
        
        //start the progress spinner (using multi-threading)
        [progress_processing setUsesThreadedAnimation:YES];
        [progress_processing startAnimation:nil];
}

/*!
 * @brief A tab view item was completed; post-process any entered data
 */
- (BOOL)didCompleteTabViewItemWithIdentifier:(NSString *)identifier
{
        BOOL success = YES;

        if ([identifier isEqualToString:ACCOUNT_SETUP_IDENTIFIER]) {
                NSString        *UID = [textField_username stringValue];

                if (UID && [UID length]) {
                        AIService       *service = [[popUp_services selectedItem] representedObject];
                        AIAccount       *account = [adium.accountController createAccountWithService:service
                                                                                                                                                                   UID:UID];
                        
                        //Save the password
                        NSString                *password = [textField_password stringValue];
                        
                        if (password && [password length] != 0) {
                                [adium.accountController setPassword:password forAccount:account];
                        }
                        AILog(@"AdiumSetupWizard: Creating account %@ on service %@",account,service);
                        //New accounts need to be added to our account list once they're configured
                        [adium.accountController addAccount:account];
                        
                        //Put new accounts online by default
                        [account setShouldBeOnline:YES];
                        
                        addedAnAccount = YES;

                } else {
                        //Successful without having a UID entered if they already added at least one account; unsuccessful otherwise.
                        success = addedAnAccount;
                }
        } else if ([identifier isEqualToString:IMPORT_IDENTIFIER]) {
                [self activateProgressIndicator];
                success = [GBFireImporter importFireConfiguration];
                addedAnAccount = [adium.accountController.accounts count] != 0;
                [progress_processing stopAnimation:nil];
                [progress_processing setHidden:YES];
        }
        
        return success;
}

/*!
 * @brief The Continue button, which is also the Done button, was pressed
 */
- (IBAction)nextTab:(id)sender
{
        NSTabViewItem *currentTabViewItem = [tabView selectedTabViewItem];
        if ([self didCompleteTabViewItemWithIdentifier:[currentTabViewItem identifier]]) {
                if ([tabView indexOfTabViewItem:currentTabViewItem] == WIZARD_TAB_DONE) {
                        //Done
                        [self  close];
                        
                } else if ([[currentTabViewItem identifier] isEqualToString:WELCOME_IDENTIFIER]) {
                        if(canImport)
                                //We can import; go to next tab
                                [tabView selectNextTabViewItem:self];
                        else
                                //No import; skip it
                                [tabView selectTabViewItemAtIndex:WIZARD_TAB_FIREIMPORT + 1];
                        
                } else {
                        //Go to the next tab view item
                        [tabView selectNextTabViewItem:self];           
                }
        } else {
                NSBeep();
        }
}

/*!
 * @brief The Back button was pressed
 */
- (IBAction)previousTab:(id)sender
{
        NSTabViewItem *currentTabViewItem = [tabView selectedTabViewItem];
        if([[currentTabViewItem identifier] isEqualToString:ACCOUNT_SETUP_IDENTIFIER] && !canImport)
                [tabView selectTabViewItemAtIndex:WIZARD_TAB_FIREIMPORT - 1];
        else
                [tabView selectPreviousTabViewItem:self];
}

/*!
 * @brief The alternate (third) button was pressed; its behavior will vary by tab view item
 */
- (IBAction)pressedAlternateButton:(id)sender
{
        NSTabViewItem   *currentTabViewItem = [tabView selectedTabViewItem];
        NSString                *identifier = [currentTabViewItem identifier];

        if ([identifier isEqualToString:ACCOUNT_SETUP_IDENTIFIER]) {
                //Configure the account
                if ([self didCompleteTabViewItemWithIdentifier:identifier]) {
                        //Reconfigure
                        [self tabView:tabView willSelectTabViewItem:currentTabViewItem];
                } else {
                        NSBeep();
                }
        } else if ([identifier isEqualToString:IMPORT_IDENTIFIER]) {
                //skip the import
                [tabView selectNextTabViewItem:self];
        }
}

/*!
 * @brief Set up the Account Setup tab for a given service
 */
- (void)configureAccountSetupForService:(AIService *)service
{
        //UID Label
        [textField_usernameLabel setStringValue:[[service userNameLabel] stringByAppendingString:AILocalizedString(@":", "Colon which will be appended after a label such as 'User Name', before an input field")]];

        //UID formatter and placeholder
        [textField_username setFormatter:
                [AIStringFormatter stringFormatterAllowingCharacters:[service allowedCharactersForAccountName]
                                                                                                          length:[service allowedLengthForAccountName]
                                                                                           caseSensitive:[service caseSensitive]
                                                                                                errorMessage:AILocalizedString(@"The characters you're entering are not valid for an account name on this service.", nil)]];
        [[textField_username cell] setPlaceholderString:[service UIDPlaceholder]];
        
        BOOL showPasswordField = ![service supportsPassword];
        [textField_passwordLabel setHidden:showPasswordField];
        [textField_password setHidden:showPasswordField];
}

- (BOOL)showAlternateButtonForIdentifier:(NSString *)identifier
{
        return [identifier isEqualToString:ACCOUNT_SETUP_IDENTIFIER] || [identifier isEqualToString:IMPORT_IDENTIFIER]; 
}

/*!
 * @brief The tab view is about to select a tab view item
 */
- (void)tabView:(NSTabView *)inTabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem
{
        NSString *identifier = [tabViewItem identifier];

        //The continue button is only initially enabled if the user has added at least one account
        [button_continue setEnabled:YES];

        if ([identifier isEqualToString:ACCOUNT_SETUP_IDENTIFIER]) {
                //Set the services menu if it hasn't already been set
                if (!setupAccountTabViewItem) {
                        [popUp_services setMenu:[AIServiceMenu menuOfServicesWithTarget:self
                                                                                                                 activeServicesOnly:NO
                                                                                                                        longDescription:YES
                                                                                                                                         format:nil]];
                        
                        [textField_addAccount setStringValue:AILocalizedString(@"Add an Instant Messaging Account",nil)];
                        [textView_addAccountMessage setDrawsBackground:NO];
                        [[textView_addAccountMessage enclosingScrollView] setDrawsBackground:NO];
                        
                        NSAttributedString *accountMessage = [AIHTMLDecoder decodeHTML:
                                AILocalizedString(@"<HTML>To chat with your friends, family, and coworkers, you must have an instant messaging account on the same service they do. Choose a service, name, and password below; if you don't have an account yet, click <A HREF=\"http://trac.adiumx.com/wiki/CreatingAnAccount#Sigingupforanaccount\">here</A> for more information.\n\nAdium supports as many accounts as you want to add; you can always add more in the Accounts pane of the Adium Preferences.</HTML>", nil)
                                                                                                         withDefaultAttributes:[[textView_addAccountMessage textStorage] attributesAtIndex:0
                                                                                                                                                                                                                                                effectiveRange:NULL]];
                        [[textView_addAccountMessage textStorage] setAttributedString:accountMessage];
                        setupAccountTabViewItem = YES;
                }

                AIService *service = [[popUp_services selectedItem] representedObject];
                [textField_username setStringValue:@""];
                [[self window] makeFirstResponder:textField_username];

                [textField_password setStringValue:@""];

                //The continue button is only initially enabled if the user has added at least one account
                [button_continue setEnabled:addedAnAccount];
                [button_alternate setLocalizedString:AILocalizedString(@"Add Another","button title for adding another account in the setup wizard")];
                [button_alternate setEnabled:NO];

                [self configureAccountSetupForService:service];

        } else if ([identifier isEqualToString:IMPORT_IDENTIFIER]) {
                [textField_import setStringValue:AILocalizedString(@"Import Fire's Settings", nil)];
                [textView_importMessage setDrawsBackground:NO];
                [[textView_importMessage enclosingScrollView] setDrawsBackground:NO];

                NSAttributedString *importMessage = [AIHTMLDecoder decodeHTML:
                        AILocalizedString(@"<HTML>Adium has detected that you have previously used Fire.  You may choose to import settings from Fire by pressing continue below.  If you choose to not use these settings, simply skip this step.<HTML>",nil)
                                                                                                withDefaultAttributes:[[textView_importMessage textStorage] attributesAtIndex:0
                                                                                                                                                                                                                           effectiveRange:NULL]];
                [[textView_importMessage textStorage] setAttributedString:importMessage];
                [button_alternate setLocalizedString:AILocalizedString(@"Skip Import","button title for skipping the import of another client in the setup wizard")];
                [button_alternate setEnabled:YES];
                
        } else if ([identifier isEqualToString:WELCOME_IDENTIFIER]) {
                [textView_welcomeMessage setDrawsBackground:NO];
                [[textView_welcomeMessage enclosingScrollView] setDrawsBackground:NO];
                NSAttributedString *welcomeMessage = [AIHTMLDecoder decodeHTML:
                        AILocalizedString(@"<HTML>Adium is <i>your</i> instant messaging solution.<br><br>Chat with whomever you want, whenever you want, however you want.  Multiple messaging services or accounts? Just one account? Work? Play? Both? No problem; Adium has you covered.<br><br>Adium is fast, free, and fun, with an interface you'll love to use day in and day out. :)<br><br>This assistant will help you set up your instant messaging accounts and get started chatting.<br><br>Click <b>Continue</b> and the duck will take it from here.</HTML>",nil)
                                                                                                 withDefaultAttributes:[[textView_addAccountMessage textStorage] attributesAtIndex:0
                                                                                                                                                                                                                                        effectiveRange:NULL]];
                //Turn that smiley into an emoticon :)
                welcomeMessage = [adium.contentController filterAttributedString:welcomeMessage
                                                                                                                   usingFilterType:AIFilterDisplay
                                                                                                                                 direction:AIFilterIncoming
                                                                                                                                   context:nil];
                [[textView_welcomeMessage textStorage] setAttributedString:welcomeMessage];

                [textField_welcome setStringValue:AILocalizedString(@"Welcome to Adium!",nil)];
                
        } else if ([identifier isEqualToString:DONE_IDENTIFIER]) {
                [textView_doneMessage setDrawsBackground:NO];
                [[textView_doneMessage enclosingScrollView] setDrawsBackground:NO];
                [textView_doneMessage setString:AILocalizedString(@"Adium is now ready for you. \n\nThe Status indicator at the top of your Contact List and in the Status menu lets you determine whether others see you as Available or Away or, alternately, if you are Offline. Select Custom to type your own status message.\n\nDouble-click a name in your Contact List to begin a conversation.  You can add contacts to your Contact List via the Contact menu.\n\nWant to customize your Adium experience? Check out the Adium Preferences and Xtras Manager via the Adium menu.\n\nEnjoy! Click Done to begin using Adium.", nil)],

                [textField_done setStringValue:AILocalizedString(@"Congratulations!","Header line in the last pane of the Adium setup wizard")];
        }

        //Hide go back on the first tab
        [button_goBack setEnabled:([tabView indexOfTabViewItem:tabViewItem] != WIZARD_TAB_WELCOME)];
        
        [button_alternate setHidden:![self showAlternateButtonForIdentifier:identifier]];

        //Set the done / continue button properly
        if ([tabView indexOfTabViewItem:tabViewItem] == WIZARD_TAB_DONE) {
                [button_continue setLocalizedString:AILocalizedString(@"Done","'done' button title")];

        } else {
                [button_continue setLocalizedString:AILocalizedString(@"Continue","'done' button title")];
        }
}

/*!
 * @brief The selected service in the account configuration tab view item was changed
 */
- (void)selectServiceType:(id)sender
{
        [self configureAccountSetupForService:[[popUp_services selectedItem] representedObject]];
}

- (void)controlTextDidChange:(NSNotification *)aNotification
{
        if ([aNotification object] == textField_username) {
                BOOL shouldEnable = ([[textField_username stringValue] length] > 0);
                //Allow continuing if they have typed something or they already added an account
                [button_continue setEnabled:(shouldEnable || addedAnAccount)];

                //Allow adding another only if they have typed something
                [button_alternate setEnabled:shouldEnable];
                
        }
}

@end