2 * Adium is the legal property of its developers, whose names are listed in the copyright file included
3 * with this source distribution.
5 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU
6 * General Public License as published by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
10 * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
11 * Public License for more details.
13 * You should have received a copy of the GNU General Public License along with this program; if not,
14 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 #import <Adium/AIAccountControllerProtocol.h>
18 #import "AIAccountProxySettings.h"
19 #import <Adium/AIContactControllerProtocol.h>
20 #import <Adium/AIPreferenceControllerProtocol.h>
21 #import "AIEditAccountWindowController.h"
22 #import <AIUtilities/AIStringAdditions.h>
23 #import <AIUtilities/AITabViewAdditions.h>
24 #import <AIUtilities/AIViewAdditions.h>
25 #import <AIUtilities/AIImageAdditions.h>
26 #import <AIUtilities/AIImageViewWithImagePicker.h>
27 #import <Adium/AIAccount.h>
28 #import <Adium/AIAccountViewController.h>
29 #import <Adium/AIService.h>
30 #import <Adium/AIService.h>
31 #import <Adium/AIServiceIcons.h>
33 @interface AIEditAccountWindowController (PRIVATE)
34 - (id)initWithWindowNibName:(NSString *)windowNibName account:(AIAccount *)inAccount notifyingTarget:(id)inTarget;
35 - (void)_addCustomViewAndTabsForAccount:(AIAccount *)inAccount;
36 - (int)_addCustomView:(NSView *)customView toView:(NSView *)setupView tabViewItemIdentifier:(NSString *)identifier
37 availableHeight:(int)height;
38 - (void)_configureResponderChain:(NSTimer *)inTimer;
39 - (void)_removeCustomViewAndTabs;
40 - (void)_localizeTabViewItemLabels;
41 - (void)saveConfiguration;
42 - (void)configureControlDimming;
46 * @class AIEditAccountWindowController
47 * @brief Window controller for configuring an <tt>AIAccount</tt>
49 @implementation AIEditAccountWindowController
52 * @brief Begin editing
54 * @param inAccount The account to edit
55 * @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.
56 * @param notifyingTarget Target to notify when editing is complete.
58 + (void)editAccount:(AIAccount *)inAccount onWindow:(id)parentWindow notifyingTarget:(id)inTarget
60 AIEditAccountWindowController *controller;
62 controller = [[self alloc] initWithWindowNibName:@"EditAccountSheet"
64 notifyingTarget:inTarget];
67 [NSApp beginSheet:[controller window]
68 modalForWindow:parentWindow
69 modalDelegate:controller
70 didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
73 [controller showWindow:nil];
78 * @brief Init the window controller
80 - (id)initWithWindowNibName:(NSString *)windowNibName account:(AIAccount *)inAccount notifyingTarget:(id)inTarget
82 if ((self = [super initWithWindowNibName:windowNibName])) {
83 account = [inAccount retain];
84 notifyTarget = inTarget;
86 didDeleteUserIcon = NO;
97 [userIconData release]; userIconData = nil;
103 * @brief Setup the window before it is displayed
105 - (void)windowDidLoad
107 //Center our window if we're not a sheet (or opening a sheet failed)
108 [[self window] center];
110 [[self window] setTitle:AILocalizedString(@"Edit Account", nil)];
113 [textField_serviceName setStringValue:[[account service] longDescription]];
114 [textField_accountDescription setStringValue:[account UID]];
116 [button_chooseIcon setLocalizedString:[AILocalizedString(@"Choose Icon",nil) stringByAppendingEllipsis]];
117 [button_OK setLocalizedString:AILocalizedString(@"OK",nil)];
118 [button_cancel setLocalizedString:AILocalizedString(@"Cancel",nil)];
119 [checkbox_autoconnect setLocalizedString:AILocalizedString(@"Connect when Adium opens", "Account preferences checkbox for automatically conencting the account when Adium opens")];
121 [[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.")];
122 [[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.")];
125 if ([account preferenceForKey:KEY_USER_ICON group:GROUP_ACCOUNT_STATUS ignoreInheritedValues:YES]) {
126 //If this account has a icon set directly on it, then it has its own icon
127 [matrix_userIcon selectCellWithTag:1];
130 //Otherwise it is using the global icon
131 [matrix_userIcon selectCellWithTag:0];
134 [imageView_userIcon setMaxSize:NSMakeSize(256, 256)];
135 [imageView_userIcon setImage:[account userIcon]];
137 [checkbox_autoconnect setState:[[account preferenceForKey:KEY_AUTOCONNECT
138 group:GROUP_ACCOUNT_STATUS] boolValue]];
140 //Insert the custom controls for this account
141 [self _removeCustomViewAndTabs];
142 [self _addCustomViewAndTabsForAccount:account];
143 [self _localizeTabViewItemLabels];
145 [self configureControlDimming];
149 * @brief Window is closing
151 - (void)windowWillClose:(id)sender
153 [super windowWillClose:sender];
158 * @brief Called as the user list edit sheet closes, dismisses the sheet
160 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
162 [sheet orderOut:nil];
165 - (void)configureControlDimming
167 BOOL enableUserIcon = ([[matrix_userIcon selectedCell] tag] == 1);
169 [imageView_userIcon setEnabled:enableUserIcon];
170 [button_chooseIcon setEnabled:enableUserIcon];
174 * @brief The user changed the selection in the icon setting matrix which determines availability of the icon controls
176 - (IBAction)changedIconSetting:(id)sender
178 [self configureControlDimming];
184 * Close without saving changes.
186 - (IBAction)cancel:(id)sender
188 if (notifyTarget) [notifyTarget editAccountSheetDidEndForAccount:account withSuccess:NO];
189 [self closeWindow:nil];
195 * Save changes and close.
197 - (IBAction)okay:(id)sender
199 [self saveConfiguration];
200 [accountViewController saveConfiguration];
201 [accountProxyController saveConfiguration];
203 if (notifyTarget) [notifyTarget editAccountSheetDidEndForAccount:account withSuccess:YES];
204 [self closeWindow:nil];
208 * @brief Save any configuration managed by the window controller
210 * Most configuration is handled by the custom view controllers. Save any other configuration, such as the user icon.
212 - (void)saveConfiguration
214 BOOL enableUserIcon = ([[matrix_userIcon selectedCell] tag] == 1);
216 if (!enableUserIcon) {
217 [userIconData release]; userIconData = nil;
218 didDeleteUserIcon = YES;
221 /* User icon - save if we have data or we deleted
222 * (so if we don't have data that's the desired thing to set as the pref) */
223 if (userIconData || didDeleteUserIcon) {
224 [account setPreference:userIconData
226 group:GROUP_ACCOUNT_STATUS];
229 [account setPreference:[NSNumber numberWithBool:[checkbox_autoconnect state]]
230 forKey:KEY_AUTOCONNECT
231 group:GROUP_ACCOUNT_STATUS];
235 * @brief Add the custom views for an account
237 - (void)_addCustomViewAndTabsForAccount:(AIAccount *)inAccount
239 NSRect windowFrame = [[self window] frame];
240 int baseHeight = [view_accountSetup frame].size.height;
241 int newHeight = baseHeight;
243 //Configure our account and proxy view controllers
244 accountViewController = [[[inAccount service] accountViewController] retain];
245 [accountViewController configureForAccount:inAccount];
247 accountProxyController = ([[inAccount service] supportsProxySettings] ?
248 [[AIAccountProxySettings alloc] init] :
250 [accountProxyController configureForAccount:inAccount];
253 newHeight = [self _addCustomView:[accountViewController setupView]
254 toView:view_accountSetup
255 tabViewItemIdentifier:@"account"
256 availableHeight:newHeight];
258 //Account Profile View
259 newHeight = [self _addCustomView:[accountViewController profileView]
260 toView:view_accountProfile
261 tabViewItemIdentifier:@"profile"
262 availableHeight:newHeight];
264 //Account Options view
265 newHeight = [self _addCustomView:[accountViewController optionsView]
266 toView:view_accountOptions
267 tabViewItemIdentifier:@"options"
268 availableHeight:newHeight];
270 //Account Privacy view
271 newHeight = [self _addCustomView:[accountViewController privacyView]
272 toView:view_accountPrivacy
273 tabViewItemIdentifier:@"privacy"
274 availableHeight:newHeight];
277 newHeight = [self _addCustomView:[accountProxyController view]
278 toView:view_accountProxy
279 tabViewItemIdentifier:@"proxy"
280 availableHeight:newHeight];
282 //Resize our window as necessary to make room for the custom views
283 windowFrame.size.height += newHeight - [view_accountSetup frame].size.height;
284 [[self window] setFrame:windowFrame display:YES];
286 //Responder chains are a pain in 10.3. The tab view will set them up correctly when we switch tabs, but doesn't
287 //get a chance to setup the responder chain for our default tab. A quick hack to get the tab view to set things
288 //up correctly is to switch tabs away and then back to our default. This causes little harm, since our window
289 //isn't visible at this point anyway.
290 //XXX - I believe we're getting a method that will avoid the need for this hack in 10.4 -ai
291 [tabView_auxiliary selectLastTabViewItem:nil];
292 [tabView_auxiliary selectFirstTabViewItem:nil];
296 * @brief Used when configuring to add custom views and remove tabs as necessary
298 * Add customView to setupView and return the height difference between the two if customView is taller than setupView.
299 * Remove the tabViewItem with the passed identifier if no customView exists, avoiding empty tabs.
301 * @param customView The view to add
302 * @param setupView The view within our nib which will be filled by customView
303 * @param identifier Identifier of the <tt>NSTabViewItem</tt> which will be removed from tabView_auxiliary if customView == nil
304 * @param requiredHeight The current required view height to display all our views
305 * @result The new required window height to display our existing views and the newly added view
307 - (int)_addCustomView:(NSView *)customView toView:(NSView *)setupView tabViewItemIdentifier:(NSString *)identifier
308 availableHeight:(int)height
311 //Adjust height as necessary if our view needs more room
312 if ([customView frame].size.height > height) {
313 height = [customView frame].size.height;
316 //Align our view to the top and insert it into the window
317 [customView setFrameOrigin:NSMakePoint(0, [setupView frame].size.height - [customView frame].size.height)];
318 [customView setAutoresizingMask:NSViewMinYMargin];
319 [setupView addSubview:customView];
322 //If no view is available, remove the corresponding tab
323 [tabView_auxiliary removeTabViewItem:[tabView_auxiliary tabViewItemWithIdentifier:identifier]];
330 * @brief Remove any existing custom views
332 - (void)_removeCustomViewAndTabs
334 //Close any currently open controllers
335 [view_accountSetup removeAllSubviews];
336 [accountViewController release]; accountViewController = nil;
340 * @brief Localization
342 - (void)_localizeTabViewItemLabels
344 [[tabView_auxiliary tabViewItemWithIdentifier:@"account"] setLabel:AILocalizedString(@"Account",nil)];
345 [[tabView_auxiliary tabViewItemWithIdentifier:@"profile"] setLabel:AILocalizedString(@"Personal",nil)];
346 [[tabView_auxiliary tabViewItemWithIdentifier:@"options"] setLabel:AILocalizedString(@"Options",nil)];
347 [[tabView_auxiliary tabViewItemWithIdentifier:@"privacy"] setLabel:AILocalizedString(@"Privacy",nil)];
348 [[tabView_auxiliary tabViewItemWithIdentifier:@"proxy"] setLabel:AILocalizedString(@"Proxy",nil)];
352 // AIImageViewWithImagePicker Delegate ---------------------------------------------------------------------
353 #pragma mark AIImageViewWithImagePicker Delegate
354 - (void)imageViewWithImagePicker:(AIImageViewWithImagePicker *)sender didChangeToImageData:(NSData *)imageData
356 [userIconData release];
357 userIconData = [imageData retain];
360 - (void)deleteInImageViewWithImagePicker:(AIImageViewWithImagePicker *)sender
362 [userIconData release]; userIconData = nil;
363 didDeleteUserIcon = YES;
365 //User icon - restore to the default icon
366 [imageView_userIcon setImage:[account userIcon]];
368 //We're now using the global icon
369 [matrix_userIcon selectCellWithTag:0];
372 - (NSString *)fileNameForImageInImagePicker:(AIImageViewWithImagePicker *)picker
374 return [[account displayName] safeFilenameString];