Unescape the HREF attribute's text before passing it to NSURL which does not expect...
[adiumx.git] / Source / ESAddressBookIntegrationAdvancedPreferences.m
blob55e26c6e1818c2513616506f9401a3fd1b4cb8ca
1 /* 
2  * Adium is the legal property of its developers, whose names are listed in the copyright file included
3  * with this source distribution.
4  * 
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.
8  * 
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.
12  * 
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.
15  */
17 #import "ESAddressBookIntegrationAdvancedPreferences.h"
18 #import "ESAddressBookIntegrationPlugin.h"
19 #import <Adium/AIContactControllerProtocol.h>
20 #import <Adium/AIPreferenceControllerProtocol.h>
21 #import <Adium/AILocalizationTextField.h>
22 #import <AIUtilities/AIDictionaryAdditions.h>
23 #import <AIUtilities/AIImageAdditions.h>
24 #import <AIUtilities/AIMenuAdditions.h>
26 #define ADDRESS_BOOK_FIRST_OPTION                                       AILocalizedString(@"First","Address Book Name display style, e.g. Evan")
27 #define ADDRESS_BOOK_FIRST_LAST_OPTION                          AILocalizedString(@"First Last","Address Book Name display style, e.g. Evan Schoenberg")
28 #define ADDRESS_BOOK_LAST_FIRST_OPTION                          AILocalizedString(@"Last, First","Address Book Name display style, e.g. Schoenberg, Evan")
29 #define ADDRESS_BOOK_LAST_FIRST_NO_COMMA_OPTION         AILocalizedString(@"Last First", "Address Book Name display style, e.g. Schoenberg Evan")
30 #define ADDRESS_BOOK_FIRST_MIDDLE_OPTION                        AILocalizedString(@"First Middle", "Address Book Name display style, e.g. Evan Dreskin")
31 #define ADDRESS_BOOK_FIRST_MIDDLE_LAST_OPTION           AILocalizedString(@"First Middle Last", "Address Book Name display style, e.g. Evan Dreskin Schoenberg")
32 #define ADDRESS_BOOK_LAST_FIRST_MIDDLE_OPTION           AILocalizedString(@"Last, First Middle", "Address Book Name display style, e.g. Schoenberg, Evan Dreskin")
33 #define ADDRESS_BOOK_LAST_FIRST_MIDDLE_NO_COMMA_OPTION  AILocalizedString(@"Last First Middle", "Address Book Name display style, e.g. Schoenberg Evan Dreskin")
34 #define ADDRESS_BOOK_FIRST_LAST_INITIAL                         AILocalizedString(@"First Last-Initial", "Address Book Name display style, e.g. Evan S")
35 #define ADDRESS_BOOK_FIRST_MIDDLE_LAST_INITIAL          AILocalizedString(@"First Middle Last-Initial", "Address Book Name display style, e.g. Evan Dreskin S")
37 @interface ESAddressBookIntegrationAdvancedPreferences (PRIVATE)
38 - (void)preferencesChanged:(NSNotification *)notification;
39 - (void)configureFormatMenu;
40 - (IBAction)changeFormat:(id)sender;
41 @end
43 /*!
44  * @class ESAddressBookIntegrationAdvancedPreferences
45  * @brief Provide advanced preferences for the address book integration
46  */
47 @implementation ESAddressBookIntegrationAdvancedPreferences
49 /*!
50  * @brief Label
51  */
52 - (NSString *)label{
53     return AILocalizedString(@"Address Book",nil);
55 /*!
56  * @brief Nib name
57  */
58 - (NSString *)nibName{
59     return @"AddressBookPrefs";
61 /*!
62  * @brief Image for advanced preferences
63  */
64 - (NSImage *)image{
65         return [NSImage imageNamed:@"AddressBook" forClass:[self class]];
68 /*!
69  * @brief Configure the preference view
70  */
71 - (void)viewDidLoad
73         [self configureFormatMenu];
74         
75         [label_formatNamesAs setLocalizedString:AILocalizedString(@"Format name as:", "Format name as: [popup menu of choices like 'First, Last']")];
76         [label_names setLocalizedString:AILocalizedString(@"Names",nil)];
77         [label_images setLocalizedString:AILocalizedString(@"Images",nil)];
78         [label_contacts setLocalizedString:AILocalizedString(@"Contacts",nil)];
79         
80         [checkBox_enableImport setLocalizedString:AILocalizedString(@"Import my contacts' names from the Address Book",nil)];
81         [checkBox_useNickName setLocalizedString:AILocalizedString(@"Use nickname if available",nil)];
82         [checkBox_useMiddleName setLocalizedString:AILocalizedString(@"Use middle name if available",nil)];
83         [checkBox_useABImages setLocalizedString:AILocalizedString(@"Use Address Book images as contacts' icons",nil)];
84         [checkBox_preferABImages setLocalizedString:AILocalizedString(@"Even if the contact already has a contact icon",nil)];
85         [checkBox_syncAutomatic setLocalizedString:AILocalizedString(@"Overwrite Address Book images with contacts' icons",nil)];
86         [checkBox_metaContacts setLocalizedString:AILocalizedString(@"Combine contacts listed on a single card",nil)];  
88         [checkBox_enableImport setState:[[[adium preferenceController] preferenceForKey:KEY_AB_ENABLE_IMPORT
89                                                                                                                                                           group:PREF_GROUP_ADDRESSBOOK] boolValue]];
90         [popUp_formatMenu selectItemAtIndex:[popUp_formatMenu indexOfItemWithTag:[[[adium preferenceController] preferenceForKey:KEY_AB_DISPLAYFORMAT
91                                                                                                                                                                                                                                            group:PREF_GROUP_ADDRESSBOOK] intValue]]];
92         [checkBox_useNickName setState:[[[adium preferenceController] preferenceForKey:KEY_AB_USE_NICKNAME
93                                                                                                                                                          group:PREF_GROUP_ADDRESSBOOK] boolValue]];
94         [checkBox_useMiddleName setState:[[[adium preferenceController] preferenceForKey:KEY_AB_USE_MIDDLE
95                                                                                                                                                            group:PREF_GROUP_ADDRESSBOOK] boolValue]];
96         [checkBox_syncAutomatic setState:[[[adium preferenceController] preferenceForKey:KEY_AB_IMAGE_SYNC
97                                                                                                                                                            group:PREF_GROUP_ADDRESSBOOK] boolValue]];
98         [checkBox_useABImages setState:[[[adium preferenceController] preferenceForKey:KEY_AB_USE_IMAGES
99                                                                                                                                                          group:PREF_GROUP_ADDRESSBOOK] boolValue]];
100         [checkBox_enableNoteSync setState:[[[adium preferenceController] preferenceForKey:KEY_AB_NOTE_SYNC
101                                                                                                                                                                 group:PREF_GROUP_ADDRESSBOOK] boolValue]];
102         [checkBox_preferABImages setState:[[[adium preferenceController] preferenceForKey:KEY_AB_PREFER_ADDRESS_BOOK_IMAGES
103                                                                                                                                                                 group:PREF_GROUP_ADDRESSBOOK] boolValue]];
104         [checkBox_metaContacts setState:[[[adium preferenceController] preferenceForKey:KEY_AB_CREATE_METACONTACTS
105                                                                                                                                                           group:PREF_GROUP_ADDRESSBOOK] boolValue]];
106         
107         [self configureControlDimming];
111  * @brief Deallocate
112  */
113 - (void)dealloc
115         [super dealloc];
119  * @brief Configure control dimming
120  */
121 - (void)configureControlDimming
123         BOOL            enableImport = [[[adium preferenceController] preferenceForKey:KEY_AB_ENABLE_IMPORT
124                                                                                                                                                          group:PREF_GROUP_ADDRESSBOOK] boolValue];
125         BOOL            useImages = [[[adium preferenceController] preferenceForKey:KEY_AB_USE_IMAGES
126                                                                                                                                                   group:PREF_GROUP_ADDRESSBOOK] boolValue];
127         
128         //Use Nick Name and the format menu are irrelevent if importing of names is not enabled
129         [checkBox_useNickName setEnabled:enableImport]; 
130         [popUp_formatMenu setEnabled:enableImport];
131         [checkBox_useMiddleName setEnabled:enableImport];
133         //We will not allow image syncing if AB images are preferred
134         //so disable the control and uncheck the box to indicate this to the user
135         //dchoby98: why are image import and export linked?
136         //[checkBox_syncAutomatic setEnabled:!preferABImages];
137         //if (preferABImages)
138         //      [checkBox_syncAutomatic setState:NSOffState];
139         
140         //Disable the image priority checkbox if we aren't using images
141         [checkBox_preferABImages setEnabled:useImages];
145  * @brief Configure the menu of name formats
146  */
147 - (void)configureFormatMenu
149     NSMenu                      *choicesMenu = [[[NSMenu allocWithZone:[NSMenu menuZone]] init] autorelease];
150     NSMenuItem          *menuItem;
151         NSString                *firstTitle, *firstLastTitle, *lastFirstTitle, *lastFirstNoCommaTitle, *firstLastInitial;
152         
153         BOOL                    useMiddleName = [[[adium preferenceController] preferenceForKey:KEY_AB_USE_MIDDLE
154                                                                                                                                                           group:PREF_GROUP_ADDRESSBOOK] boolValue];
155         
156         //If the use middle name preference is set, we use the menu titles that include a middle name
157         if (useMiddleName) {
158                 firstTitle = ADDRESS_BOOK_FIRST_MIDDLE_OPTION;
159                 firstLastTitle = ADDRESS_BOOK_FIRST_MIDDLE_LAST_OPTION;
160                 lastFirstTitle = ADDRESS_BOOK_LAST_FIRST_MIDDLE_OPTION;
161                 lastFirstNoCommaTitle = ADDRESS_BOOK_LAST_FIRST_MIDDLE_NO_COMMA_OPTION;
162                 firstLastInitial = ADDRESS_BOOK_FIRST_MIDDLE_LAST_INITIAL;
164         //Otherwise we use the standard menu titles
165         } else {
166                 firstTitle = ADDRESS_BOOK_FIRST_OPTION;
167                 firstLastTitle = ADDRESS_BOOK_FIRST_LAST_OPTION;
168                 lastFirstTitle = ADDRESS_BOOK_LAST_FIRST_OPTION;
169                 lastFirstNoCommaTitle = ADDRESS_BOOK_LAST_FIRST_NO_COMMA_OPTION;
170                 firstLastInitial = ADDRESS_BOOK_FIRST_LAST_INITIAL;
171         }
172         
173         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:firstTitle
174                                                                                                                                          target:self
175                                                                                                                                          action:@selector(changeFormat:)
176                                                                                                                           keyEquivalent:@""] autorelease];
177     [menuItem setTag:First];
178     [choicesMenu addItem:menuItem];
179         
180     menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:firstLastTitle
181                                                                                                                                          target:self
182                                                                                                                                          action:@selector(changeFormat:)
183                                                                                                                           keyEquivalent:@""] autorelease];
184     [menuItem setTag:FirstLast];
185     [choicesMenu addItem:menuItem];
186     
187     menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:lastFirstTitle
188                                                                                                                                          target:self
189                                                                                                                                          action:@selector(changeFormat:)
190                                                                                                                           keyEquivalent:@""] autorelease];
191     [menuItem setTag:LastFirst];
192     [choicesMenu addItem:menuItem];
193         
194         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:lastFirstNoCommaTitle
195                                                                                                                                          target:self
196                                                                                                                                          action:@selector(changeFormat:)
197                                                                                                                           keyEquivalent:@""] autorelease];
198         [menuItem setTag:LastFirstNoComma];
199         [choicesMenu addItem:menuItem];
201         menuItem = [[[NSMenuItem allocWithZone:[NSMenu menuZone]] initWithTitle:firstLastInitial
202                                                                                                                                          target:self
203                                                                                                                                          action:@selector(changeFormat:)
204                                                                                                                           keyEquivalent:@""] autorelease];
205         [menuItem setTag:FirstLastInitial];
206         [choicesMenu addItem:menuItem];
208     [popUp_formatMenu setMenu:choicesMenu];
209         
210     NSRect oldFrame = [popUp_formatMenu frame];
211     [popUp_formatMenu setFrameOrigin:oldFrame.origin];
212         [[self view] setNeedsDisplay:YES];
216  * @brief Save changed name format preference
217  */
218 - (IBAction)changeFormat:(id)sender
220         [[adium preferenceController] setPreference:[NSNumber numberWithInt:[sender tag]]
221                                             forKey:KEY_AB_DISPLAYFORMAT
222                                             group:PREF_GROUP_ADDRESSBOOK];
226  * @brief Save changed preference
227  */
228 - (IBAction)changePreference:(id)sender
230     if (sender == checkBox_syncAutomatic) {
231         [[adium preferenceController] setPreference:[NSNumber numberWithBool:([sender state]==NSOnState)]
232                                              forKey:KEY_AB_IMAGE_SYNC
233                                               group:PREF_GROUP_ADDRESSBOOK];
234                 
235     } else if (sender == checkBox_useABImages) {
236         [[adium preferenceController] setPreference:[NSNumber numberWithBool:([sender state]==NSOnState)]
237                                              forKey:KEY_AB_USE_IMAGES
238                                               group:PREF_GROUP_ADDRESSBOOK];
239                 
240     } else if (sender == checkBox_useNickName) {
241         [[adium preferenceController] setPreference:[NSNumber numberWithBool:([sender state]==NSOnState)]
242                                              forKey:KEY_AB_USE_NICKNAME
243                                               group:PREF_GROUP_ADDRESSBOOK];
244                 
245         } else if (sender == checkBox_useMiddleName) {
246                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:([sender state] == NSOnState)]
247                                                                                          forKey:KEY_AB_USE_MIDDLE
248                                                                                           group:PREF_GROUP_ADDRESSBOOK];
249                 //Update the format menu to reflect the use of middle names
250                 [self configureFormatMenu];
251                 
252     } else if (sender == checkBox_enableImport) {
253         [[adium preferenceController] setPreference:[NSNumber numberWithBool:([sender state] == NSOnState)]
254                                              forKey:KEY_AB_ENABLE_IMPORT
255                                               group:PREF_GROUP_ADDRESSBOOK];
256                 
257     } else if (sender == checkBox_preferABImages) {
258         [[adium preferenceController] setPreference:[NSNumber numberWithBool:([sender state] == NSOnState)]
259                                              forKey:KEY_AB_PREFER_ADDRESS_BOOK_IMAGES
260                                               group:PREF_GROUP_ADDRESSBOOK];
261                 
262     } else if (sender == checkBox_enableNoteSync) {
263         [[adium preferenceController] setPreference:[NSNumber numberWithBool:([sender state] == NSOnState)]
264                                              forKey:KEY_AB_NOTE_SYNC
265                                               group:PREF_GROUP_ADDRESSBOOK];
266                 
267     } else if (sender == checkBox_metaContacts) {
268                 BOOL shouldCreateMetaContacts = ([sender state] == NSOnState);
269                 
270                 if (shouldCreateMetaContacts) {
271                         [[adium preferenceController] setPreference:[NSNumber numberWithBool:YES]
272                                                                                                  forKey:KEY_AB_CREATE_METACONTACTS
273                                                                                                   group:PREF_GROUP_ADDRESSBOOK];                
274                         
275                 } else {
276                         NSBeginAlertSheet(nil,
277                                                           AILocalizedString(@"Unconsolidate all metacontacts",nil),
278                                                           AILocalizedString(@"Cancel",nil), nil,
279                                                           [[self view] window], self,
280                                                           @selector(sheetDidEnd:returnCode:contextInfo:), NULL,
281                                                           NULL,
282                                                           AILocalizedString(@"Disabling automatic contact consolidation will also unconsolidate all existing metacontacts, including any created manually.  You will need to recreate any manually-created metacontacts if you proceed.",nil));
283                 }
284         }
286     [self configureControlDimming];
289 - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
291         if (returnCode == NSAlertDefaultReturn) {
292                 //If we now shouldn't create metaContacts, clear 'em all... not pretty, but effective.
294                 //Delay to the next run loop to give better UI responsiveness
295                 [[adium contactController] performSelector:@selector(clearAllMetaContactData)
296                                                                                 withObject:nil
297                                                                                 afterDelay:0.0001];
298                 
299                 
300                 [[adium preferenceController] setPreference:[NSNumber numberWithBool:NO]
301                                              forKey:KEY_AB_CREATE_METACONTACTS
302                                               group:PREF_GROUP_ADDRESSBOOK];            
303         } else {
304                 //Put the checkbox back
305                 [checkBox_metaContacts setState:![checkBox_metaContacts state]];
306         }
309 @end