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 / AIEditAccountWindowController.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
405
406
407
408
409
410
411
412
413
414
415
416
417
418
/*
 * Adium is the legal property of its developers, whose names are listed in the copyright file included
 * with this source distribution.
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
 * General Public License as published by the Free Software Foundation; either version 2 of the License,
 * or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not,
 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

#import <Adium/AIAccountControllerProtocol.h>
#import "AIAccountProxySettings.h"
#import <Adium/AIContactControllerProtocol.h>
#import "AIEditAccountWindowController.h"
#import <AIUtilities/AIStringAdditions.h>
#import <AIUtilities/AITabViewAdditions.h>
#import <AIUtilities/AIViewAdditions.h>
#import <AIUtilities/AIImageAdditions.h>
#import <AIUtilities/AIImageViewWithImagePicker.h>
#import <Adium/AIAccount.h>
#import <Adium/AIAccountViewController.h>
#import <Adium/AIService.h>
#import <Adium/AIService.h>
#import <Adium/AIServiceIcons.h>

@interface AIEditAccountWindowController ()
- (id)initWithWindowNibName:(NSString *)windowNibName account:(AIAccount *)inAccount notifyingTarget:(id)inTarget;
- (void)_addCustomViewAndTabsForAccount:(AIAccount *)inAccount;
- (void)_addCustomView:(NSView *)customView toView:(NSView *)setupView tabViewItemIdentifier:(NSString *)identifier
                runningHeight:(NSInteger *)height width:(NSInteger *)width;
- (void)_removeCustomViewAndTabs;
- (void)_localizeTabViewItemLabels;
- (void)saveConfiguration;
- (void)configureControlDimming;
@end

/*!
 * @class AIEditAccountWindowController
 * @brief Window controller for configuring an <tt>AIAccount</tt>
 */
@implementation AIEditAccountWindowController

/*!
 * @brief Begin editing
 *
 * @param inAccount The account to edit
 * @param parentWindow A window on which to show the edit account window as a sheet.  If nil, account editing takes place in an independent window.
 * @param inTarget Target to notify when editing is complete.
 */
+ (void)editAccount:(AIAccount *)inAccount onWindow:(id)parentWindow notifyingTarget:(id)inTarget
{
        AIEditAccountWindowController   *controller;

        controller = [[self alloc] initWithWindowNibName:@"EditAccountSheet"
                                                                                         account:inAccount
                                                                         notifyingTarget:inTarget];

        if (parentWindow) {
                [NSApp beginSheet:[controller window]
                   modalForWindow:parentWindow
                        modalDelegate:controller
                   didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
                          contextInfo:nil];
        } else {
                [controller showWindow:nil];
        }
}

/*!
 * @brief Init the window controller
 */
- (id)initWithWindowNibName:(NSString *)windowNibName account:(AIAccount *)inAccount notifyingTarget:(id)inTarget
{
        if ((self = [super initWithWindowNibName:windowNibName])) {
                account = [inAccount retain];
                notifyTarget = inTarget;
                userIconData = nil;
                didDeleteUserIcon = NO;
        }
        return self;
}

/*!
 * @brief Deallocate
 */
- (void)dealloc
{
        [account release];
        [userIconData release]; userIconData = nil;

        [super dealloc];
}

/*!
 * @brief Setup the window before it is displayed
 */
- (void)windowDidLoad
{
        //Center our window if we're not a sheet (or opening a sheet failed)
        [[self window] center];
        
        [[self window] setTitle:AILocalizedString(@"Edit Account", nil)];

        //Account Overview
        [textField_serviceName setStringValue:[account.service longDescription]];
        [textField_accountDescription setStringValue:account.UID];

        [button_chooseIcon setLocalizedString:[AILocalizedString(@"Choose Icon",nil) stringByAppendingEllipsis]];
        [button_OK setLocalizedString:AILocalizedString(@"OK",nil)];
        [button_cancel setLocalizedString:AILocalizedString(@"Cancel",nil)];
        [checkbox_autoconnect setLocalizedString:AILocalizedString(@"Connect when Adium opens", "Account preferences checkbox for automatically conencting the account when Adium opens")];

        [[matrix_userIcon cellWithTag:0] setTitle:AILocalizedString(@"Use global icon", "Radio button in the Personal tab of Account preferences.  This -must- be a short string of 20 characters or less.")];
        [[matrix_userIcon cellWithTag:1] setTitle:AILocalizedString(@"Use this icon:", "Radio button in the Personal tab of Account preferences; an image is shown beneath it to select the account's icon.  This -must- be a short string of 20 characters or less.")];
        
        //User icon
        if ([[account preferenceForKey:KEY_USE_USER_ICON group:GROUP_ACCOUNT_STATUS] boolValue]) {
                //If this account has the preference set, use its user icon.
                [matrix_userIcon selectCellWithTag:1];

        } else {
                //Otherwise it is using the global icon
                [matrix_userIcon selectCellWithTag:0];
        }

        [imageView_userIcon setMaxSize:NSMakeSize(256, 256)];
        [imageView_userIcon setImage:[account userIcon]];

        [checkbox_autoconnect setState:[[account preferenceForKey:KEY_AUTOCONNECT
                                                                                                                group:GROUP_ACCOUNT_STATUS] boolValue]];

        //Insert the custom controls for this account
        [self _removeCustomViewAndTabs];
        [self _addCustomViewAndTabsForAccount:account];
        [self _localizeTabViewItemLabels];
        
        [self configureControlDimming];
}

- (IBAction)showWindow:(id)sender {
        [super showWindow:sender];
        if([notifyTarget respondsToSelector:@selector(editAccountWindow:didOpenForAccount:)])
                [notifyTarget editAccountWindow:[self window] didOpenForAccount:account];
}

/*!
 * @brief Window is closing
 */
- (void)windowWillClose:(id)sender
{
        [super windowWillClose:sender];
        [self autorelease];
}

/*!
 * @brief Called as the user list edit sheet closes, dismisses the sheet
 */
- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo
{
    [sheet orderOut:nil];
}

- (void)configureControlDimming
{
        BOOL enableUserIcon = ([[matrix_userIcon selectedCell] tag] == 1);
        
        [imageView_userIcon setEnabled:enableUserIcon];
        [button_chooseIcon setEnabled:enableUserIcon];
}

/*!
 * @brief The user changed the selection in the icon setting matrix which determines availability of the icon controls
 */
- (IBAction)changedIconSetting:(id)sender
{
        [self configureControlDimming];
}

/*!
 * @brief Cancel
 *
 * Close without saving changes.
 */
- (IBAction)cancel:(id)sender
{
        if (notifyTarget) [notifyTarget editAccountSheetDidEndForAccount:account withSuccess:NO];
        [self closeWindow:nil];
}

/*!
 * @brief Okay.
 *
 * Save changes and close.
 */
- (IBAction)okay:(id)sender
{
        [self saveConfiguration];
        [accountViewController saveConfiguration];
        [accountProxyController saveConfiguration];
        
        [account accountEdited];

        if (notifyTarget) [notifyTarget editAccountSheetDidEndForAccount:account withSuccess:YES];
        [self closeWindow:nil];
}

/*!
 * @brief Save any configuration managed by the window controller
 *
 * Most configuration is handled by the custom view controllers.  Save any other configuration, such as the user icon.
 */
- (void)saveConfiguration
{
        BOOL enableUserIcon = ([[matrix_userIcon selectedCell] tag] == 1);

        if (!enableUserIcon) {
                [userIconData release]; userIconData = nil;
                didDeleteUserIcon = YES;
        }

        /* User icon - save if we have data or we deleted
         * (so if we don't have data that's the desired thing to set as the pref) */
        if (userIconData || didDeleteUserIcon) {
                [account setPreference:userIconData
                                                forKey:KEY_USER_ICON
                                                 group:GROUP_ACCOUNT_STATUS];
        }
        
        [account setPreference:[NSNumber numberWithBool:[[matrix_userIcon selectedCell] tag]]
                                        forKey:KEY_USE_USER_ICON
                                         group:GROUP_ACCOUNT_STATUS];

        [account setPreference:[NSNumber numberWithBool:[checkbox_autoconnect state]]
                                        forKey:KEY_AUTOCONNECT
                                         group:GROUP_ACCOUNT_STATUS];
}

/*!
 * @brief Add the custom views for an account
 */
- (void)_addCustomViewAndTabsForAccount:(AIAccount *)inAccount
{
        NSRect  windowFrame = [[self window] frame];
        NSInteger               baseHeight = NSHeight([view_accountSetup frame]);
        NSInteger               baseWidth = NSWidth([view_accountSetup frame]);
        NSInteger               newHeight = baseHeight, newWidth = baseWidth;

        //Configure our account and proxy view controllers
        accountViewController = [[inAccount.service accountViewController] retain];
        [accountViewController configureForAccount:inAccount];

        accountProxyController = ([inAccount.service supportsProxySettings] ?
                                                          [[AIAccountProxySettings alloc] init] :
                                                          nil);
        [accountProxyController configureForAccount:inAccount];

        //Account setup view
        [self _addCustomView:[accountViewController setupView]
                                  toView:view_accountSetup
   tabViewItemIdentifier:@"account"
                 runningHeight:&newHeight
                                   width:&newWidth];
        
        //Account Profile View
        [self _addCustomView:[accountViewController profileView]
                                  toView:view_accountProfile
   tabViewItemIdentifier:@"profile"
                 runningHeight:&newHeight
                                   width:NULL];
        
        //Account Options view
        [self _addCustomView:[accountViewController optionsView]
                                  toView:view_accountOptions
   tabViewItemIdentifier:@"options"
                 runningHeight:&newHeight
                                   width:&newWidth];
        
        //Account Privacy view
        [self _addCustomView:[accountViewController privacyView]
                                  toView:view_accountPrivacy
   tabViewItemIdentifier:@"privacy"
                 runningHeight:&newHeight
                                   width:&newWidth];
        
        //Add proxy view
        [self _addCustomView:[accountProxyController view]
                                  toView:view_accountProxy
   tabViewItemIdentifier:@"proxy"
                 runningHeight:&newHeight
                                   width:&newWidth];
        
        //Resize our window as necessary to make room for the custom views
        windowFrame.size.height += newHeight - baseHeight;
        windowFrame.size.width += newWidth - baseWidth;

        [[self window] setFrame:windowFrame display:YES];

        //Responder chains are a pain in 10.3.  The tab view will set them up correctly when we switch tabs, but doesn't
        //get a chance to setup the responder chain for our default tab.  A quick hack to get the tab view to set things
        //up correctly is to switch tabs away and then back to our default.  This causes little harm, since our window
        //isn't visible at this point anyway.
        //XXX - I believe we're getting a method that will avoid the need for this hack in 10.4 -ai
        [tabView_auxiliary selectLastTabViewItem:nil];
        [tabView_auxiliary selectFirstTabViewItem:nil];
}

/*!
 * @brief Used when configuring to add custom views and remove tabs as necessary
 *
 * Add customView to setupView and return the height difference between the two if customView is taller than setupView.
 * Remove the tabViewItem with the passed identifier if no customView exists, avoiding empty tabs.
 *
 * @param customView The view to add
 * @param setupView The view within our nib which will be filled by customView
 * @param identifier Identifier of the <tt>NSTabViewItem</tt> which will be removed from tabView_auxiliary if customView == nil
 * @param requiredHeight The current required view height to display all our views
 * @result The new required window height to display our existing views and the newly added view
 */
- (void)_addCustomView:(NSView *)customView toView:(NSView *)setupView tabViewItemIdentifier:(NSString *)identifier
          runningHeight:(NSInteger *)height width:(NSInteger *)width
{
        if (customView) {
                //Adjust height as necessary if our view needs more room
                if (NSHeight([customView frame]) > *height) {
                        *height = NSHeight([customView frame]);
                }

                //Adjust height as necessary if our view needs more room
                if (width && (NSWidth([customView frame]) > *width)) {
                        *width = NSWidth([customView frame]);
                }
                
                //Align our view to the top and insert it into the window
                if (width && (NSWidth([setupView frame]) > NSWidth([customView frame])))
                        [customView setFrameOrigin:NSMakePoint(floor((NSWidth([setupView frame]) - NSWidth([customView frame])) / 2),
                                                                                                   NSHeight([setupView frame]) - NSHeight([customView frame]))];
                else
                        [customView setFrameOrigin:NSMakePoint(0,
                                                                                                   NSHeight([setupView frame]) - NSHeight([customView frame]))];

                [customView setAutoresizingMask:(NSViewMinYMargin | NSViewMinXMargin | NSViewMaxXMargin)];
                [setupView addSubview:customView];

        } else {
                //If no view is available, remove the corresponding tab
                [tabView_auxiliary removeTabViewItem:[tabView_auxiliary tabViewItemWithIdentifier:identifier]];
        }
}

/*!
 * @brief Remove any existing custom views
 */
- (void)_removeCustomViewAndTabs
{
    //Close any currently open controllers
    [view_accountSetup removeAllSubviews];
    [accountViewController release]; accountViewController = nil;
}

/*!
 * @brief Localization
 */
- (void)_localizeTabViewItemLabels
{
        [[tabView_auxiliary tabViewItemWithIdentifier:@"account"] setLabel:AILocalizedString(@"Account",nil)];
        [[tabView_auxiliary tabViewItemWithIdentifier:@"profile"] setLabel:AILocalizedString(@"Personal",nil)];
        [[tabView_auxiliary tabViewItemWithIdentifier:@"options"] setLabel:AILocalizedString(@"Options",nil)];
        [[tabView_auxiliary tabViewItemWithIdentifier:@"privacy"] setLabel:AILocalizedString(@"Privacy",nil)];
        [[tabView_auxiliary tabViewItemWithIdentifier:@"proxy"] setLabel:AILocalizedString(@"Proxy",nil)];
}


// AIImageViewWithImagePicker Delegate ---------------------------------------------------------------------
#pragma mark AIImageViewWithImagePicker Delegate
- (void)deleteInImageViewWithImagePicker:(AIImageViewWithImagePicker *)sender
{
        [userIconData release]; userIconData = nil;
        didDeleteUserIcon = YES;

        //User icon - restore to the default icon
        [imageView_userIcon setImage:[account userIcon]];
        
        //We're now using the global icon
        [matrix_userIcon selectCellWithTag:0];
}

- (void)imageViewWithImagePicker:(AIImageViewWithImagePicker *)sender didChangeToImageData:(NSData *)imageData
{
        [userIconData release];
        userIconData = [imageData retain];
        
        if (!userIconData) {
                //If we got a nil user icon, that means the icon was deleted
                [self deleteInImageViewWithImagePicker:sender];
        }
}

- (NSString *)fileNameForImageInImagePicker:(AIImageViewWithImagePicker *)picker
{
        NSString *fileName = [account.displayName safeFilenameString];
        if ([fileName hasPrefix:@"."]) {
                fileName = [fileName substringFromIndex:1];
        }
        return fileName;
}

- (NSImage *)emptyPictureImageForImageViewWithImagePicker:(AIImageViewWithImagePicker *)picker
{
        return [AIServiceIcons serviceIconForObject:account type:AIServiceIconLarge direction:AIIconNormal];
}

@end