PageRenderTime 69ms CodeModel.GetById 13ms app.highlight 51ms RepoModel.GetById 2ms app.codeStats 0ms

/Source/externals/GData/Examples/ContactsSample/EditEntryWindowController.m

http://google-email-uploader-mac.googlecode.com/
Objective C | 386 lines | 259 code | 79 blank | 48 comment | 50 complexity | acfb7b6c03fc0d91aa7f113ffb33a14e MD5 | raw file
  1/* Copyright (c) 2008 Google Inc.
  2*
  3* Licensed under the Apache License, Version 2.0 (the "License");
  4* you may not use this file except in compliance with the License.
  5* You may obtain a copy of the License at
  6*
  7*     http://www.apache.org/licenses/LICENSE-2.0
  8*
  9* Unless required by applicable law or agreed to in writing, software
 10* distributed under the License is distributed on an "AS IS" BASIS,
 11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12* See the License for the specific language governing permissions and
 13* limitations under the License.
 14*/
 15
 16//
 17//  EditEntryWindowController.m
 18//
 19
 20#import "EditEntryWindowController.h"
 21#import "GData/GDataEntryContact.h"
 22#import "GData/GDataEntryContactGroup.h"
 23
 24
 25// map from class of item to display name for item and the item's object
 26// selectors to use for various editable fields in the nib
 27//
 28// for example, the value displayed will be obtained with stringValue
 29// for postal address objects but with address for IM objects
 30//
 31// nil means "disable this edit field"
 32typedef struct ItemSelectors {
 33  NSString *className;
 34  NSString *classDisplayName;
 35  NSString *valueKey;
 36  NSString *labelKey;
 37  NSString *relKey;
 38  NSString *titleKey;
 39  NSString *protocolKey;
 40} ItemSelectors;
 41
 42static ItemSelectors sAllItemSelectors[] = {
 43  { @"GDataOrganization",            @"Organization",      @"orgName",            @"label", @"rel", @"orgTitle", nil         },
 44  { @"GDataEmail",                   @"E-mail",            @"address",            @"label", @"rel", nil,         nil         },
 45  { @"GDataIM",                      @"Instant Messaging", @"address",            @"label", @"rel", nil,         @"protocol" },
 46  { @"GDataPhoneNumber",             @"Phone",             @"stringValue",        @"label", @"rel", nil,         nil         },
 47  { @"GDataStructuredPostalAddress", @"Postal",            @"formattedAddress",   @"label", @"rel", nil,         nil         },
 48  { @"GDataGroupMembershipInfo",     @"Group",             nil,                   nil,      nil,    nil,         nil         },
 49  { @"GDataExtendedProperty",        @"Extended Property", @"unifiedStringValue", @"name",  nil,    nil,         nil         },
 50  { 0, 0, 0, 0, 0, 0 }
 51};
 52
 53
 54// given the object we're editing, get the list with the selectors
 55// and the display name for that class of object
 56static ItemSelectors *ItemSelectorsForObject(GDataObject *obj) {
 57  
 58  NSString *className = NSStringFromClass([obj class]);
 59  
 60  for (int idx = 0; sAllItemSelectors[idx].className; idx++) {
 61
 62    if ([className isEqual:sAllItemSelectors[idx].className]) {
 63      return &sAllItemSelectors[idx]; 
 64    }
 65  }
 66  return NULL;
 67}
 68
 69@interface EditEntryWindowController (PrivateMethods)
 70- (void)setUIFromObject:(GDataObject *)obj;
 71@end
 72
 73@implementation EditEntryWindowController
 74
 75- (id)init {
 76  return [self initWithWindowNibName:@"EditEntryWindow"];
 77}
 78
 79- (void)awakeFromNib {
 80  
 81  if (mObject) {
 82    // copy data from the object to our dialog's controls
 83    [self setUIFromObject:mObject];
 84  }
 85  
 86  // make the lists of rel values for the rel combo box, and put in a dictionary
 87  // according to item class.  This dictionary is used for the combo box
 88  // data source delegate methods
 89  //
 90  // When the combo box menu's data source asks for the menu items,
 91  // we'll just look up the rel strings from the class of the item
 92  // being edited.
 93  
 94  NSArray *standardRels = [NSArray arrayWithObjects:kGDataContactHome,
 95    kGDataContactWork, kGDataContactOther, nil];
 96  
 97  NSArray *orgRels = [NSArray arrayWithObjects:kGDataContactWork, 
 98    kGDataContactOther, nil];
 99  
100  NSArray *phoneRels = [NSArray arrayWithObjects:kGDataPhoneNumberHome, 
101    kGDataPhoneNumberMobile, kGDataPhoneNumberPager, kGDataPhoneNumberWork,
102    kGDataPhoneNumberHomeFax, kGDataPhoneNumberWorkFax, kGDataPhoneNumberOther,
103    nil];
104
105  NSArray *noRels = [NSArray array];
106  
107  relsDict_ = [[NSDictionary alloc] initWithObjectsAndKeys:
108    orgRels, @"GDataOrganization",
109    standardRels, @"GDataEmail",
110    standardRels, @"GDataIM",
111    phoneRels, @"GDataPhoneNumber",
112    standardRels, @"GDataStructuredPostalAddress", 
113    noRels, @"GDataGroupMembershipInfo", 
114    noRels, @"GDataExtendedProperty", nil];
115}
116
117- (void)dealloc {
118  [relsDict_ release];
119  [mObject release];
120  [mGroupFeed release];
121  [super dealloc]; 
122}
123
124
125
126#pragma mark -
127
128// given a key, get the value from the object for that key, or an empty string
129- (NSString *)stringValueForKey:(NSString *)key object:(GDataObject *)obj {
130  if (key) {
131    NSString *value = [obj valueForKey:key];
132    if (value) {
133      return value;
134    }
135  }
136  return @"";
137}
138
139- (void)setUIFromObject:(GDataObject *)obj {
140  
141  ItemSelectors *sels = ItemSelectorsForObject(obj);
142  
143  NSString *value = [self stringValueForKey:(sels->valueKey) object:obj];
144  NSString *label = [self stringValueForKey:(sels->labelKey) object:obj];
145  NSString *rel = [self stringValueForKey:(sels->relKey) object:obj];
146  NSString *title = [self stringValueForKey:(sels->titleKey) object:obj];
147  NSString *protocol = [self stringValueForKey:(sels->protocolKey) object:obj];
148
149  [mClassNameField setStringValue:(sels->classDisplayName)];
150  
151  [mValueField setStringValue:value];
152  [mLabelField setStringValue:label];
153  [mRelField setStringValue:rel];
154  [mOrgTitleField setStringValue:title];
155  [mProtocolField setStringValue:protocol];
156
157  [mValueField setEnabled:(sels->valueKey != nil)];
158  [mLabelField setEnabled:(sels->labelKey != nil)];
159  [mRelField setEnabled:(sels->relKey != nil)];
160  [mOrgTitleField setEnabled:(sels->titleKey != nil)];
161  [mProtocolField setEnabled:(sels->protocolKey != nil)];
162  
163  // group combo box
164  if ([obj isKindOfClass:[GDataGroupMembershipInfo class]]) {
165    [mGroupField setEnabled:YES];
166    
167    // set the field text to the group namefor this object's href
168    NSString *objectID = [(GDataGroupMembershipInfo *)obj href];
169    if (objectID) {
170      GDataEntryContactGroup *groupEntry = [mGroupFeed entryForIdentifier:objectID];
171      NSString *name = [[groupEntry title] stringValue];
172      [mGroupField setStringValue:name];
173    }
174  } else {
175    [mGroupField setEnabled:NO];
176  }
177  
178  // "primary" checkbox
179  if ([obj respondsToSelector:@selector(isPrimary)]) {
180    BOOL isPrimary = [(id)obj isPrimary];
181    [mPrimaryCheckbox setState:(isPrimary ? NSOnState : NSOffState)];
182    [mPrimaryCheckbox setEnabled:YES];
183  } else {
184    [mPrimaryCheckbox setEnabled:NO];
185  }
186
187  // "deleted" checkbox
188  if ([obj respondsToSelector:@selector(isDeleted)]) {
189    BOOL isDeleted = [(id)obj isDeleted];
190    [mDeletedCheckbox setState:(isDeleted ? NSOnState : NSOffState)];
191    [mDeletedCheckbox setEnabled:YES];
192  } else {
193    [mDeletedCheckbox setEnabled:NO];
194  }
195  
196}
197
198- (NSString *)stringValueOrNilForField:(NSTextField *)field {
199  NSString *str = [field stringValue];
200  return ([str length] > 0) ? str : nil;
201}
202
203- (GDataObject *)objectFromUI {
204  
205  ItemSelectors *sels = ItemSelectorsForObject(mObject);
206  
207  NSString *value = [self stringValueOrNilForField:mValueField];
208  NSString *label = [self stringValueOrNilForField:mLabelField];
209  NSString *rel = [self stringValueOrNilForField:mRelField];
210  NSString *title = [self stringValueOrNilForField:mOrgTitleField];
211  NSString *protocol = [self stringValueOrNilForField:mProtocolField];
212  
213  GDataObject *newObj = [mObject copy];
214  
215  if (sels->valueKey)    [newObj setValue:value forKey:sels->valueKey];
216  if (sels->labelKey)    [newObj setValue:label forKey:sels->labelKey];
217  if (sels->relKey)      [newObj setValue:rel forKey:sels->relKey];
218  if (sels->titleKey)    [newObj setValue:title forKey:sels->titleKey];
219  if (sels->protocolKey) [newObj setValue:protocol forKey:sels->protocolKey];
220  
221  if ([mPrimaryCheckbox isEnabled]) {
222    BOOL isPrimary = ([mPrimaryCheckbox state] == NSOnState);
223    [(id)newObj setIsPrimary:isPrimary];
224  }
225
226  if ([mDeletedCheckbox isEnabled]) {
227    BOOL isDeleted = ([mDeletedCheckbox state] == NSOnState);
228    [(id)newObj setIsDeleted:isDeleted];
229  }
230  
231  if ([mGroupField isEnabled]) {
232    // find the index of the group entry that has the title in the combo box
233    NSString *str = [mGroupField stringValue];
234    NSArray *titles = [mGroupFeed valueForKeyPath:@"entries.title.stringValue"];
235    int index = [titles indexOfObject:str];
236
237    NSString *href;
238    if (index != NSNotFound) {
239      // we found the title; get the corresponding entry's ID
240      href = [[[mGroupFeed entries] objectAtIndex:index] identifier];
241    } else {
242      // it wasn't a title, so assume the user entered a group's ID
243      href = str; 
244    }
245    [(id)newObj setHref:href];
246  }
247  
248  return newObj;
249}
250
251
252
253#pragma mark -
254
255- (void)runModalForTarget:(id)target
256                 selector:(SEL)doneSelector
257                groupFeed:(GDataFeedContactGroup *)groupFeed
258                   object:(GDataObject *)object
259{
260  
261  mTarget = target;
262  mDoneSEL = doneSelector;
263  mObject = [object retain];
264  mGroupFeed = [groupFeed retain];
265  
266  [NSApp beginSheet:[self window]
267     modalForWindow:[mTarget window]
268      modalDelegate:self
269     didEndSelector:@selector(sheetDidEnd:returnCode:contextInfo:)
270        contextInfo:nil];
271}
272
273- (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode  contextInfo:(void  *)contextInfo {
274  
275}
276
277- (void)closeDialog {
278  // call the target to say we're done
279  [mTarget performSelector:mDoneSEL 
280                withObject:[[self retain] autorelease]];
281  
282  [[self window] orderOut:self];
283  [NSApp endSheet:[self window]];
284}
285
286- (IBAction)saveButtonClicked:(id)sender {
287  mWasSaveClicked = YES;
288  [self closeDialog];
289}
290
291- (IBAction)cancelButtonClicked:(id)sender {
292  [self closeDialog];
293}
294
295- (GDataObject *)object {
296  // copy from our dialog's controls into the object
297  return [self objectFromUI]; 
298}
299
300- (BOOL)wasSaveClicked {
301  return mWasSaveClicked; 
302}
303
304#pragma mark Rel and Protocol combo box data source
305
306- (NSArray *)relsForCurrentObject {
307  NSString *className = NSStringFromClass([mObject class]);
308  return [relsDict_ objectForKey:className];
309}
310
311- (NSArray *)protocolsForCurrentObject {
312  
313  if ([mObject class] == [GDataIM class]) {
314    
315    return [NSArray arrayWithObjects:
316      kGDataIMProtocolAIM, kGDataIMProtocolGoogleTalk, kGDataIMProtocolICQ,
317      kGDataIMProtocolJabber, kGDataIMProtocolMSN, kGDataIMProtocolYahoo, nil];
318  }
319  return nil;
320}
321
322- (int)numberOfItemsInComboBox:(NSComboBox *)aComboBox {
323  if (aComboBox == mRelField) {
324    return [[self relsForCurrentObject] count];
325  } else if (aComboBox == mGroupField) {
326    return [[mGroupFeed entries] count];
327  } else {
328    return [[self protocolsForCurrentObject] count];
329  }
330}
331
332- (id)comboBox:(NSComboBox *)aComboBox objectValueForItemAtIndex:(int)index {
333  if (aComboBox == mRelField) {
334    return [[self relsForCurrentObject] objectAtIndex:index];
335  } else if (aComboBox == mGroupField) {
336    NSArray *titles = [mGroupFeed valueForKeyPath:@"entries.title.stringValue"];
337    return [titles objectAtIndex:index];
338  } else {
339    return [[self protocolsForCurrentObject] objectAtIndex:index];
340  }
341}
342
343@end
344
345
346@implementation GDataExtendedProperty (ContactsSampleAdditions)
347// getter that looks for a plain value or for an XML array;
348// setter that looks for a leading "<" to decide if it's an XML element
349
350- (NSString *)unifiedStringValue {
351  
352  NSString *result = [self value];
353  if (result == nil) {
354    NSArray *xmlStrings  = [[self XMLValues] valueForKey:@"XMLString"];
355    result = [xmlStrings componentsJoinedByString:@""];
356  }
357  return result; 
358}
359
360- (void)setUnifiedStringValue:(NSString *)str {
361  NSCharacterSet *wsSet = [NSCharacterSet whitespaceAndNewlineCharacterSet];
362  NSString *trimmed = [str stringByTrimmingCharactersInSet:wsSet];
363  
364  if ([trimmed hasPrefix:@"<"]) {
365    
366    // set as an XML element
367    NSError *error = nil;
368    NSXMLElement *element;
369    element = [[[NSXMLElement alloc] initWithXMLString:str
370                                                 error:&error] autorelease];
371    if (element) {
372      [self setXMLValues:[NSArray arrayWithObject:element]];
373    } else {
374      NSLog(@"XML parse error: %@", error);
375      [self setXMLValues:nil];
376    }
377    [self setValue:nil];
378
379  } else {
380    
381    // set as an attribute string
382    [self setValue:str];
383    [self setXMLValues:nil];
384  }
385}
386@end