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 "AIAccountController.h"
18 #import "AIAccountProxySettings.h"
19 #import "AIContactController.h"
20 #import "AIPreferenceController.h"
21 #import "AIEditAccountWindowController.h"
22 #import <AIUtilities/AIStringAdditions.h>
23 #import <AIUtilities/AITabViewAdditions.h>
24 #import <AIUtilities/AIViewAdditions.h>
25 #import <AIUtilities/ESImageAdditions.h>
26 #import <AIUtilities/ESImageViewWithImagePicker.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 isNewAccount:(BOOL)inIsNewAccount;
35 - (void)_addCustomViewAndTabsForAccount:(AIAccount *)inAccount;
36 - (int)_addCustomView:(NSView *)customView toView:(NSView *)setupView tabViewItemIdentifier:(NSString *)identifier;
37 - (void)_configureResponderChain:(NSTimer *)inTimer;
38 - (void)_removeCustomViewAndTabs;
39 - (void)_localizeTabViewItemLabels;
40 - (void)saveConfiguration;
44 * @class AIEditAccountWindowController
45 * @brief Window controller for configuring an <tt>AIAccount</tt>
47 @implementation AIEditAccountWindowController
50 * @brief Begin editing
52 * @param inAccount The account to edit
53 * @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.
54 * @param inIsNewAccount If YES and the user presses cancel, inAccount is deleted. This should be passed as YES when the method is called as a result of creating a new account.
56 + (void)editAccount:(AIAccount *)inAccount onWindow:(id)parentWindow isNewAccount:(BOOL)inIsNewAccount
58 AIEditAccountWindowController *controller;
60 controller = [[self alloc] initWithWindowNibName:@"EditAccountSheet"
62 isNewAccount:inIsNewAccount];
65 [NSApp beginSheet:[controller window]
66 modalForWindow:parentWindow
67 modalDelegate:controller
68 didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
71 [controller showWindow:nil];
76 * @brief Init the window controller
78 - (id)initWithWindowNibName:(NSString *)windowNibName account:(AIAccount *)inAccount isNewAccount:(BOOL)inIsNewAccount
80 if((self = [super initWithWindowNibName:windowNibName])) {
81 account = [inAccount retain];
82 isNewAccount = inIsNewAccount;
84 didDeleteUserIcon = NO;
95 [userIconData release]; userIconData = nil;
101 * @brief Setup the window before it is displayed
103 - (void)windowDidLoad
105 //Center our window if we're not a sheet (or opening a sheet failed)
106 [[self window] center];
110 [image_serviceIcon setImage:[AIServiceIcons serviceIconForService:[account service]
111 type:AIServiceIconLarge
112 direction:AIIconNormal]];
114 [textField_serviceName setStringValue:[[account service] longDescription]];
115 [textField_accountDescription setStringValue:[account UID]];
116 [checkBox_autoConnect setState:[[account preferenceForKey:@"AutoConnect" group:GROUP_ACCOUNT_STATUS] boolValue]];
117 [checkBox_autoConnect setLocalizedString:AILocalizedString(@"Automatically connect on launch","Accounts preferences: When Adium loads, connect this account immediately.")];
118 [button_chooseIcon setLocalizedString:[AILocalizedString(@"Choose Icon",nil) stringByAppendingEllipsis]];
119 [button_OK setLocalizedString:AILocalizedString(@"OK",nil)];
120 [button_cancel setLocalizedString:AILocalizedString(@"Cancel",nil)];
123 [imageView_userIcon setImage:[account userIcon]];
125 //Insert the custom controls for this account
126 [self _removeCustomViewAndTabs];
127 [self _addCustomViewAndTabsForAccount:account];
128 [self _localizeTabViewItemLabels];
132 * @brief Window is closing
134 - (void)windowWillClose:(id)sender
136 [super windowWillClose:sender];
141 * @brief Called as the user list edit sheet closes, dismisses the sheet
143 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
145 [sheet orderOut:nil];
151 * Close without saving changes. If isNewAccount is YES, delete the account at this time.
152 * isNewAccount should only be YES if we were called to edit a newly created account. Canceling the process should
153 * delete the account which we were passed.
155 - (IBAction)cancel:(id)sender
158 [[adium accountController] deleteAccount:account save:YES];
161 [self closeWindow:nil];
167 * Save changes and close.
169 - (IBAction)okay:(id)sender
171 [self saveConfiguration];
172 [accountViewController saveConfiguration];
173 [accountProxyController saveConfiguration];
174 [self closeWindow:nil];
176 //Put new accounts online by default
178 [account setPreference:[NSNumber numberWithBool:YES] forKey:@"Online" group:GROUP_ACCOUNT_STATUS];
184 * @brief Save any configuration managed by the window controller
186 * Most configuration is handled by the custom view controllers. Save any other configuration, such as the user icon.
188 - (void)saveConfiguration
190 /* User icon - save if we have data or we deleted
191 * (so if we don't have data that's the desired thing to set as the pref) */
192 if(userIconData || didDeleteUserIcon){
193 [account setPreference:userIconData
195 group:GROUP_ACCOUNT_STATUS];
199 [account setPreference:[NSNumber numberWithBool:[checkBox_autoConnect state]]
200 forKey:@"AutoConnect"
201 group:GROUP_ACCOUNT_STATUS];
205 * @brief Add the custom views for an account
207 - (void)_addCustomViewAndTabsForAccount:(AIAccount *)inAccount
210 int heightChange = 0;
211 int heightDifference;
213 windowFrame = [[self window] frame];
215 //Configure our account and proxy view controllers
216 accountViewController = [[[inAccount service] accountViewController] retain];
217 [accountViewController configureForAccount:inAccount];
219 accountProxyController = ([[inAccount service] supportsProxySettings] ?
220 [[AIAccountProxySettings alloc] init] :
222 [accountProxyController configureForAccount:inAccount];
225 heightDifference = [self _addCustomView:[accountViewController setupView]
226 toView:view_accountSetup
227 tabViewItemIdentifier:@"account"];
228 if(heightDifference > heightChange) heightChange = heightDifference;
230 //Account Profile View
231 heightDifference = [self _addCustomView:[accountViewController profileView]
232 toView:view_accountProfile
233 tabViewItemIdentifier:@"profile"];
234 if(heightDifference > heightChange) heightChange = heightDifference;
236 //Account Options view
237 heightDifference = [self _addCustomView:[accountViewController optionsView]
238 toView:view_accountOptions
239 tabViewItemIdentifier:@"options"];
240 if(heightDifference > heightChange) heightChange = heightDifference;
242 //Account Privacy view
243 heightDifference = [self _addCustomView:[accountViewController privacyView]
244 toView:view_accountPrivacy
245 tabViewItemIdentifier:@"privacy"];
246 if(heightDifference > heightChange) heightChange = heightDifference;
249 heightDifference = [self _addCustomView:[accountProxyController view]
250 toView:view_accountProxy
251 tabViewItemIdentifier:@"proxy"];
252 if(heightDifference > heightChange) heightChange = heightDifference;
254 windowFrame.size.height += heightChange;
255 [[self window] setFrame:windowFrame display:YES];
257 //Responder chains are a pain in 10.3. The tab view will set them up correctly when we switch tabs, but doesn't
258 //get a chance to setup the responder chain for our default tab. A quick hack to get the tab view to set things
259 //up correctly is to switch tabs away and then back to our default. This causes little harm, since our window
260 //isn't visible at this point anyway.
261 //XXX - I believe we're getting a method that will avoid the need for this hack in 10.4 -ai
262 [tabView_auxiliary selectLastTabViewItem:nil];
263 [tabView_auxiliary selectFirstTabViewItem:nil];
267 * @brief Used when configuring to add custom views and remove tabs as necessary
269 * Add customView to setupView and return the height difference between the two if customView is taller than setupView.
270 * Remove the tabViewItem with the passed identifier if no customView exists, avoiding empty tabs.
272 * @param customView The view to add
273 * @param setupView The view within our nib which will be filled by customView
274 * @param identifier Identifier of the <tt>NSTabViewItem</tt> which will be removed from tabView_auxiliary if customView == nil
275 * @result The positive height difference betwen customView and setupView, indicating how much taller the window needs to be to fit customView.
277 - (int)_addCustomView:(NSView *)customView toView:(NSView *)setupView tabViewItemIdentifier:(NSString *)identifier
279 NSSize customViewFrameSize;
281 int heightDifference;
284 customViewFrameSize = [customView frame].size;
285 ourViewFrame = [setupView frame];
287 heightDifference = (customViewFrameSize.height - ourViewFrame.size.height);
288 if(heightDifference > 0){
289 //Modify our frame to make room
290 ourViewFrame.size.height += heightDifference;
291 ourViewFrame.origin.y -= heightDifference;
292 [setupView setFrame:ourViewFrame];
295 [customView setFrameSize:ourViewFrame.size];
296 [setupView addSubview:customView];
298 //If no options are available, remove the options tab
299 [tabView_auxiliary removeTabViewItem:[tabView_auxiliary tabViewItemWithIdentifier:identifier]];
301 heightDifference = 0;
304 return(heightDifference > 0 ? heightDifference : 0);
308 * @brief Remove any existing custom views
310 - (void)_removeCustomViewAndTabs
312 //Close any currently open controllers
313 [view_accountSetup removeAllSubviews];
314 [accountViewController release]; accountViewController = nil;
318 * @brief Localization
320 - (void)_localizeTabViewItemLabels
322 [[tabView_auxiliary tabViewItemWithIdentifier:@"account"] setLabel:AILocalizedString(@"Account",nil)];
323 [[tabView_auxiliary tabViewItemWithIdentifier:@"profile"] setLabel:AILocalizedString(@"Personal",nil)];
324 [[tabView_auxiliary tabViewItemWithIdentifier:@"options"] setLabel:AILocalizedString(@"Options",nil)];
325 [[tabView_auxiliary tabViewItemWithIdentifier:@"privacy"] setLabel:AILocalizedString(@"Privacy",nil)];
326 [[tabView_auxiliary tabViewItemWithIdentifier:@"proxy"] setLabel:AILocalizedString(@"Proxy",nil)];
329 // ESImageViewWithImagePicker Delegate ---------------------------------------------------------------------
330 - (void)imageViewWithImagePicker:(ESImageViewWithImagePicker *)sender didChangeToImageData:(NSData *)imageData
332 [userIconData release];
333 userIconData = [imageData retain];
336 - (void)deleteInImageViewWithImagePicker:(ESImageViewWithImagePicker *)sender
338 [userIconData release]; userIconData = nil;
339 didDeleteUserIcon = YES;
341 //User icon - restore to the default icon
342 [imageView_userIcon setImage:[account userIcon]];