]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/SettingsBundle/CNBrowseDomainsController.m
mDNSResponder-1096.60.2.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / SettingsBundle / CNBrowseDomainsController.m
1 /*
2 *
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #import "CNBrowseDomainsController.h"
19 #import "CNDomainBrowserViewController.h"
20 #import "CNDomainBrowserPathUtils.h"
21 #import "BonjourSCStore.h"
22 #import <AssertMacros.h>
23
24 #define kTag_AddBrowse 100
25 #define kTag_AddManual 101
26
27 const NSString * _CNBrowseDomainKey_fullname = (NSString *)SC_DYNDNS_DOMAIN_KEY;
28 const NSString * _CNBrowseDomainKey_enabled = (NSString *)SC_DYNDNS_ENABLED_KEY;
29
30 #define LocalizedStringFromMyBundle(key, comment ) \
31 NSLocalizedStringFromTableInBundle(key, @"Localizable", [NSBundle bundleForClass: [self class]], comment )
32
33 @interface CNPathPopoverViewController : UIViewController
34
35 @property (strong) UILabel * label;
36 @property (copy) NSArray * pathArray;
37 @property (assign) CGPoint offset;
38
39 @end
40
41 @implementation CNPathPopoverViewController
42
43 - (instancetype)initWithPathArray:(NSArray *)pathArray
44 {
45 if (self = [self initWithNibName: nil bundle: nil] )
46 {
47 _pathArray = pathArray;
48 NSMutableParagraphStyle * paragraphStyle = [[NSMutableParagraphStyle alloc] init];
49 [paragraphStyle setLineSpacing: [UIFont labelFontSize] * 0.3];
50
51 NSMutableAttributedString * itemStr = [[NSMutableAttributedString alloc] init];
52 NSUInteger count = 0;
53 for (NSString * next in _pathArray )
54 {
55 NSString * nextLine = [NSString stringWithFormat: @"%@%@", itemStr.length ? @"\n" : @"", next];
56 UIColor * nextColor = ((count++ == 0) || (count == _pathArray.count)) ? [UIColor grayColor] : [UIColor blackColor];
57 [itemStr appendAttributedString:
58 [[NSMutableAttributedString alloc] initWithString: nextLine
59 attributes: @{ NSForegroundColorAttributeName: nextColor,
60 NSParagraphStyleAttributeName: paragraphStyle
61 }]];
62 }
63
64 _label = [[UILabel alloc] initWithFrame: CGRectZero];
65 _label.numberOfLines = 0;
66 _label.attributedText = itemStr;
67 [_label sizeToFit];
68
69 _offset = CGPointMake(25, 15 );
70 CGRect rect = _label.frame;
71 rect.origin.x += _offset.x;
72 rect.origin.y += _offset.y;
73 [_label setFrame: rect];
74 }
75 return(self );
76 }
77
78 - (void)viewDidLoad
79 {
80 [super viewDidLoad];
81 [self.view addSubview: _label];
82 }
83
84 - (void)willTransitionToTraitCollection:(UITraitCollection *)newCollection withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinator
85 {
86 [super willTransitionToTraitCollection: newCollection withTransitionCoordinator: coordinator];
87 [self.presentingViewController dismissViewControllerAnimated: NO completion: nil];
88 }
89
90 @end
91
92 @interface CNPathAccessoryView : UIView
93
94 @property (strong, readonly) UIButton * elipsisButton;
95 @property (strong, readonly) UIButton * pathLabel;
96 @property (weak) UITableView * tableView;
97 @property (weak) UITableViewCell * cell;
98 @property (strong, readonly) NSArray * pathArray;
99
100 @end
101
102 @implementation CNPathAccessoryView
103
104 - (instancetype) initWithFrame:(CGRect)frame pathArray:(NSArray *)pathArray
105 {
106 self = [super initWithFrame:frame];
107 if (self) {
108 _pathArray = pathArray;
109 if (_pathArray )
110 {
111 _pathLabel = [UIButton buttonWithType: UIButtonTypeCustom];
112 [_pathLabel setTitle: _pathArray[_pathArray.count-1] forState: UIControlStateNormal];
113 [_pathLabel setTitleColor: [UIColor blackColor] forState: UIControlStateNormal];
114 _pathLabel.titleLabel.font = [UIFont systemFontOfSize: [UIFont labelFontSize]];
115 [self addSubview: _pathLabel];
116
117 _pathLabel.translatesAutoresizingMaskIntoConstraints = NO;
118 [_pathLabel sizeToFit];
119 [_pathLabel.widthAnchor constraintEqualToConstant: _pathLabel.frame.size.width].active = YES;
120 [_pathLabel.trailingAnchor constraintEqualToAnchor: self.trailingAnchor].active = YES;
121 [_pathLabel.topAnchor constraintEqualToAnchor: self.topAnchor].active = YES;
122 [_pathLabel.bottomAnchor constraintEqualToAnchor: self.bottomAnchor].active = YES;
123 }
124 if (_pathArray.count > 2 )
125 {
126 _elipsisButton = [UIButton buttonWithType: UIButtonTypeCustom];
127 [_elipsisButton setTitle: @"…" forState: UIControlStateNormal];
128 [_elipsisButton setTitleColor: _elipsisButton.tintColor forState: UIControlStateNormal];
129 [_elipsisButton setTitleColor: [UIColor grayColor] forState: UIControlStateHighlighted];
130 _elipsisButton.titleLabel.font = [UIFont boldSystemFontOfSize: [UIFont labelFontSize]];
131 [_elipsisButton addTarget: self action: @selector(pathButtonPressed:withEvent:) forControlEvents: UIControlEventTouchUpInside];
132 _elipsisButton.userInteractionEnabled = YES;
133 [self addSubview: _elipsisButton];
134
135 _elipsisButton.translatesAutoresizingMaskIntoConstraints = NO;
136 [_elipsisButton sizeToFit];
137 [_elipsisButton.widthAnchor constraintEqualToConstant: _elipsisButton.frame.size.width].active = YES;
138 [_elipsisButton.trailingAnchor constraintEqualToAnchor: _pathLabel.leadingAnchor].active = YES;
139 [_elipsisButton.topAnchor constraintGreaterThanOrEqualToAnchor: self.topAnchor].active = YES;
140 [_elipsisButton.bottomAnchor constraintLessThanOrEqualToAnchor: self.bottomAnchor].active = YES;
141 }
142 }
143 return self;
144 }
145
146 - (BOOL) canBecomeFirstResponder
147 {
148 return YES;
149 }
150
151 - (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection
152 {
153 (void)controller; // Unused
154 (void)traitCollection; // Unused
155 return UIModalPresentationNone;
156 }
157
158 - (void) pathButtonPressed:(UIControl *)button withEvent:(UIEvent *)event
159 {
160 (void)button; // Unused
161
162 if (!self.cell.showingDeleteConfirmation )
163 {
164 [self becomeFirstResponder];
165
166 UIView *buttonView = [[event.allTouches anyObject] view];
167 CGRect buttonFrame = [buttonView convertRect: buttonView.frame toView: self];
168
169 CNPathPopoverViewController * controller = [[CNPathPopoverViewController alloc] initWithPathArray: self.pathArray];
170 controller.modalPresentationStyle = UIModalPresentationPopover;
171 controller.preferredContentSize = CGSizeMake(controller.label.frame.size.width + controller.offset.x * 2, controller.label.frame.size.height + controller.offset.y * 2 );
172
173 UIPopoverPresentationController *popover = controller.popoverPresentationController;
174 popover.delegate = (id<UIPopoverPresentationControllerDelegate>)self;
175 popover.sourceView = buttonView;
176 popover.sourceRect = buttonFrame;
177 popover.permittedArrowDirections = UIPopoverArrowDirectionLeft | UIPopoverArrowDirectionRight;
178
179 [(UIViewController *)self.tableView.delegate presentViewController: controller
180 animated: YES
181 completion: nil];
182 }
183 }
184
185 - (CGSize) sizeThatFits:(CGSize)size
186 {
187 (void)size; // Unused
188 CGSize ret = CGSizeZero;
189 CGFloat maxX = 0.0;
190 CGFloat maxHeight = 0.0;
191 for (UIView *view in [self subviews] )
192 {
193 CGRect frame = view.frame;
194 CGFloat frameMaxX = CGRectGetMaxX(frame);
195 CGFloat frameHeight = CGRectGetHeight(frame);
196 maxX += frameMaxX;
197 if (frameHeight > maxHeight )
198 {
199 maxHeight = frameHeight;
200 }
201 }
202 ret.width = maxX;
203 ret.height = maxHeight;
204 return ret;
205 }
206
207 @end
208
209 @interface CNManualDomainViewController : UITableViewController
210
211 @property (weak) CNBrowseDomainsController * delegate;
212 @property (weak) UITextField * textField;
213
214 @end
215
216 #define kTag_EditTextField 103
217
218 @implementation CNManualDomainViewController
219
220 - (void)viewDidLoad
221 {
222 [super viewDidLoad];
223
224 self.tableView.dataSource = (id<UITableViewDataSource>)self;
225 self.tableView.delegate = (id<UITableViewDelegate>)self;
226
227 self.title = LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.title", nil );
228 self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.cancel", nil )
229 style: UIBarButtonItemStylePlain
230 target: self
231 action: @selector(cancelAction:)];
232
233 self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.add", nil )
234 style: UIBarButtonItemStylePlain
235 target: self
236 action: @selector(addAction:)];
237 self.navigationItem.rightBarButtonItem.enabled = NO;
238 }
239
240 - (void)viewWillDisappear:(BOOL)animated
241 {
242 [super viewWillDisappear: animated];
243 if (self.isMovingFromParentViewController )
244 {
245 [[NSNotificationCenter defaultCenter] removeObserver: self];
246 }
247 }
248
249 - (void)viewDidAppear:(BOOL)animated
250 {
251 [super viewDidAppear: animated];
252 if (self.isMovingToParentViewController )
253 {
254 [self.textField becomeFirstResponder];
255 }
256 }
257
258 - (IBAction)addAction:(id)sender
259 {
260 (void)sender; // Unused
261 [self.navigationController dismissViewControllerAnimated: YES completion: ^{
262 [self.delegate addBrowseDomain: self.textField.text];
263 }];
264 }
265
266 - (IBAction)cancelAction:(id)sender
267 {
268 (void)sender; // Unused
269 [self.navigationController dismissViewControllerAnimated: YES completion: nil];
270 }
271
272 #pragma mark - Notifications
273
274 - (void)textFieldDidChange:(NSNotification *)notification
275 {
276 UITextField * textField = (UITextField *)notification.object;
277 self.navigationItem.rightBarButtonItem.enabled = (textField.text.length > 0);
278 }
279
280 #pragma mark - TableView Delegates
281
282 - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
283 {
284 (void)tableView; // Unused
285 (void)indexPath; // Unused
286 return UITableViewAutomaticDimension;
287 }
288
289 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
290 {
291 (void)tableView; // Unused
292 NSInteger result = 0;
293
294 if (tableView == self.tableView ) result = 1;
295
296 return(result );
297 }
298
299 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
300 {
301 (void)section; // Unused
302 NSInteger result = 0;
303
304 if (tableView == self.tableView && section == 0 ) result = 1;
305
306 return(result );
307 }
308
309 - (nullable NSString *)tableView:(UITableView *)tableView titleForFooterInSection:(NSInteger)section
310 {
311 NSString * result = nil;
312
313 if (tableView == self.tableView && section == 0 )
314 {
315 result = LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.footer", nil );
316 }
317
318 return(result );
319 }
320
321 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
322 {
323 UITableViewCell *cell = nil;
324
325 if (tableView == self.tableView )
326 {
327 if (indexPath.section == 0 && indexPath.row == 0 )
328 {
329 static NSString *MyIdentifier = @"manual_domain_cell_id";
330 cell = [tableView dequeueReusableCellWithIdentifier: MyIdentifier];
331 if (!cell )
332 {
333 cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleValue1 reuseIdentifier: MyIdentifier];
334 }
335
336 cell.textLabel.hidden = YES;
337 cell.detailTextLabel.hidden = YES;
338
339 [[cell viewWithTag: kTag_EditTextField] removeFromSuperview];
340 UITextField * textField = [[UITextField alloc] initWithFrame:CGRectZero];
341 textField.tag = kTag_EditTextField;
342 textField.adjustsFontSizeToFitWidth = YES;
343 textField.placeholder = LocalizedStringFromMyBundle(@"_dnsBrowser.manualdomain.defaultValue", nil );
344 textField.keyboardType = UIKeyboardTypeURL;
345 textField.autocapitalizationType = UITextAutocapitalizationTypeNone;
346 textField.autocorrectionType = UITextAutocorrectionTypeNo;
347 textField.enablesReturnKeyAutomatically = YES;
348 textField.clearButtonMode = UITextFieldViewModeAlways;
349 [cell.contentView addSubview: textField];
350
351 textField.translatesAutoresizingMaskIntoConstraints = NO;
352 [textField.leadingAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.leadingAnchor].active = YES;
353 [textField.trailingAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.trailingAnchor].active = YES;
354 [textField.topAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.topAnchor].active = YES;
355 [textField.bottomAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.bottomAnchor].active = YES;
356
357 [[NSNotificationCenter defaultCenter] addObserver: self
358 selector: @selector(textFieldDidChange:)
359 name: UITextFieldTextDidChangeNotification
360 object: textField];
361 self.textField = textField;
362 }
363 }
364
365 return(cell );
366 }
367
368 - (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
369 {
370 (void)tableView; // Unused
371 (void)indexPath; // Unused
372 return(nil );
373 }
374
375 @end
376
377 @interface CNBrowseDomainsController ()
378
379 @property (strong) NSDictionary * selectedInstance;
380 @property (strong) NSMutableDictionary * instanceInfoStrings;
381 @property (strong) NSMutableDictionary * instanceStatusViews;
382
383 @property (strong) CNDomainBrowserViewController * browseController;
384
385 @end
386
387 @implementation CNBrowseDomainsController
388
389 - (instancetype)initWithStyle:(UITableViewStyle)style
390 {
391 if (self = [super initWithStyle: style] )
392 {
393 [self commonInit];
394 }
395 return(self );
396 }
397
398 - (void)contentViewsInit
399 {
400 self.tableView.allowsMultipleSelectionDuringEditing = NO;
401 }
402
403 - (void)commonInit
404 {
405 self.instanceInfoStrings = [NSMutableDictionary dictionary];
406 self.instanceStatusViews = [NSMutableDictionary dictionary];
407 self.browseController = [[CNDomainBrowserViewController alloc] initWithStyle: UITableViewStylePlain];
408 _browseController.delegate = (id<CNDomainBrowserViewControllerDelegate>)self;
409 _browseController.ignoreLocal = YES;
410 }
411
412 - (void)viewDidLoad
413 {
414 [super viewDidLoad];
415 [self contentViewsInit];
416
417 self.tableView.dataSource = (id<UITableViewDataSource>)self;
418 self.tableView.delegate = (id<UITableViewDelegate>)self;
419 }
420
421 - (void)viewWillAppear:(BOOL)animated
422 {
423 [super viewWillAppear: animated];
424 if (self.isMovingToParentViewController)
425 {
426 [_browseController startBrowse];
427 }
428 }
429
430 - (void)viewWillDisappear:(BOOL)animated
431 {
432 [super viewWillDisappear: animated];
433 if (self.isMovingFromParentViewController )
434 {
435 [self savePreferences];
436 [_browseController stopBrowse];
437 }
438 }
439
440 -(void)savePreferences
441 {
442 [BonjourSCStore setObject: _browseDomainsA.count ? _browseDomainsA : nil forKey: (NSString *)SC_DYNDNS_BROWSEDOMAINS_KEY];
443 }
444
445 - (NSDictionary *)browseDomainForRow:(NSInteger)row
446 {
447 NSDictionary * result = nil;
448 NSInteger curRow = 0;
449
450 for (NSDictionary * nextDomain in self.browseDomainsA )
451 {
452 if (curRow == row )
453 {
454 result = nextDomain;
455 break;
456 }
457 curRow++;
458 }
459
460 return(result );
461 }
462
463 - (NSInteger)indexOfDomainInList:(NSString *)domainString
464 {
465 NSInteger index = 0;
466 if (_browseDomainsA ) {
467 NSDictionary *domainDict;
468 NSString *domainName;
469 NSEnumerator *arrayEnumerator = [_browseDomainsA objectEnumerator];
470 while ((domainDict = [arrayEnumerator nextObject]) != NULL)
471 {
472 domainName = [domainDict objectForKey:_CNBrowseDomainKey_fullname];
473 if ([domainString caseInsensitiveCompare:domainName] == NSOrderedSame) return index;
474 index++;
475 }
476 }
477 return NSNotFound;
478 }
479
480 - (void)addBrowseDomain:(NSString *)fullPath
481 {
482 NSString * trimmedPath = TrimCharactersFromDNSDomain(fullPath );
483 NSInteger index = [self indexOfDomainInList: trimmedPath];
484 NSMutableArray * domains = [NSMutableArray arrayWithArray: self.browseDomainsA];
485
486 if (index == NSNotFound )
487 {
488 [domains addObject: @{
489 _CNBrowseDomainKey_fullname: trimmedPath,
490 _CNBrowseDomainKey_enabled: @YES
491 }];
492
493 self.browseDomainsA = [NSArray arrayWithArray: domains];
494 [self.tableView insertRowsAtIndexPaths: @[[NSIndexPath indexPathForRow: domains.count-1 inSection: 0]] withRowAnimation: UITableViewRowAnimationAutomatic];
495 }
496 else
497 {
498 NSDictionary * domain = domains[index];
499 domains[index] = @{
500 _CNBrowseDomainKey_fullname: domain[_CNBrowseDomainKey_fullname],
501 _CNBrowseDomainKey_enabled: @YES
502 };
503 self.browseDomainsA = [NSArray arrayWithArray: domains];
504 NSIndexPath * indexPath = [NSIndexPath indexPathForRow: index inSection: 0];
505 [CATransaction begin];
506 [CATransaction setCompletionBlock:^{
507 [self.tableView deselectRowAtIndexPath: indexPath animated: YES];
508 }];
509 [self.tableView reloadRowsAtIndexPaths: @[indexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
510 [self.tableView selectRowAtIndexPath: indexPath animated: YES scrollPosition: UITableViewScrollPositionMiddle];
511 [CATransaction commit];
512
513 }
514 }
515
516 #pragma mark - CNDomainBrowserViewControllerDelegate
517
518 - (void)domainBrowserDomainSelected:(NSString *)domain
519 {
520 [self newPathSelected: domain];
521 }
522
523 - (void)bonjourBrowserDomainUpdate:(NSString *)defaultDomain
524 {
525 (void)defaultDomain; // Unused
526 [self.tableView reloadData];
527 }
528
529 #pragma mark - TableView Delegates
530
531 - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
532 {
533 (void)tableView; // Unused
534 (void)indexPath; // Unused
535 return UITableViewAutomaticDimension;
536 }
537
538 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
539 {
540 (void)tableView; // Unused
541 NSInteger result = 0;
542
543 if (tableView == self.tableView ) result = (self.browseController.flattenedDNSDomains.count > 0) ? 3 : 2;
544 else result = 1;
545
546 return(result );
547 }
548
549 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
550 {
551 (void)section; // Unused
552 NSInteger result = 0;
553
554 if (tableView == self.tableView )
555 {
556 if (section == 0 )
557 {
558 result = self.browseDomainsA.count;
559 }
560 else
561 {
562 result = 1;
563 }
564 }
565
566 return(result );
567 }
568
569 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
570 {
571 UITableViewCell *cell = nil;
572
573 if (tableView == self.tableView )
574 {
575 if (indexPath.section == 0 )
576 {
577 NSDictionary * record = [self browseDomainForRow: indexPath.row];
578 if (record )
579 {
580 static NSString *MyIdentifier = @"browse_cell_id";
581 cell = [tableView dequeueReusableCellWithIdentifier: MyIdentifier];
582 if (!cell )
583 {
584 cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleSubtitle reuseIdentifier: MyIdentifier];
585 }
586 NSArray * pathArray = DNSDomainToDomainPath(record[_CNBrowseDomainKey_fullname] );
587 cell.textLabel.text = pathArray[pathArray.count-1];
588 cell.textLabel.textColor = nil;
589 cell.textLabel.numberOfLines = 0;
590 cell.accessoryType = UITableViewCellAccessoryNone;
591 cell.accessoryView = nil;
592 cell.imageView.image = [[UIImage imageNamed: @"UIPreferencesBlueCheck.png"
593 inBundle: [NSBundle bundleForClass: [self class]]
594 compatibleWithTraitCollection: nil] imageWithRenderingMode: UIImageRenderingModeAlwaysTemplate];
595 cell.imageView.hidden = ![record[_CNBrowseDomainKey_enabled] boolValue];
596
597 NSArray * accPathArray = (pathArray.count > 2) ?
598 [[pathArray reverseObjectEnumerator] allObjects] :
599 ((pathArray.count > 1) ? @[pathArray[0]] : nil);
600 if (accPathArray )
601 {
602 CNPathAccessoryView * accView = [[CNPathAccessoryView alloc] initWithFrame: CGRectZero
603 pathArray: accPathArray];
604 accView.tableView = tableView;
605 accView.cell = cell;
606 [accView sizeToFit];
607 cell.accessoryView = accView;
608 }
609 }
610 }
611 else
612 {
613 static NSString *MyIdentifier = @"button_cell_id";
614 cell = [tableView dequeueReusableCellWithIdentifier: MyIdentifier];
615 if (!cell )
616 {
617 cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: MyIdentifier];
618 }
619
620 if (self.browseController.flattenedDNSDomains.count > 0 && indexPath.section == 1 )
621 {
622 cell.textLabel.textColor = self.view.tintColor;
623 cell.textLabel.text = LocalizedStringFromMyBundle(@"_dnsBrowser.domains.selectdomain", nil );
624 cell.accessoryType = UITableViewCellAccessoryNone;
625 cell.tag = kTag_AddBrowse;
626 }
627 else
628 {
629 cell.textLabel.textColor = self.view.tintColor;
630 cell.textLabel.text = LocalizedStringFromMyBundle(@"_dnsBrowser.domains.selectmanual", nil );
631 cell.accessoryType = UITableViewCellAccessoryNone;
632 cell.tag = kTag_AddManual;
633 }
634 }
635 }
636
637 return(cell );
638 }
639
640 - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
641 {
642 BOOL result = NO;
643
644 if (tableView == self.tableView && indexPath.section == 0 ) result = YES;
645
646 return(result );
647 }
648
649 - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
650 {
651 if (editingStyle == UITableViewCellEditingStyleDelete )
652 {
653 NSMutableArray * domains = [NSMutableArray arrayWithArray: self.browseDomainsA];
654 [domains removeObjectAtIndex: indexPath.row];
655 self.browseDomainsA = [NSArray arrayWithArray: domains];
656 [tableView deleteRowsAtIndexPaths: @[indexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
657 }
658 }
659
660 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
661 {
662 UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath];
663 if (tableView == self.tableView )
664 {
665 if (indexPath.section == 0 )
666 { // Toggle check and enable bit
667 NSMutableArray * domains = [NSMutableArray arrayWithArray: self.browseDomainsA];
668 NSMutableDictionary * selection = [NSMutableDictionary dictionaryWithDictionary: domains[indexPath.row]];
669 selection[_CNBrowseDomainKey_enabled] = [NSNumber numberWithBool: ![selection[_CNBrowseDomainKey_enabled] boolValue]];
670 domains[indexPath.row] = selection;
671 self.browseDomainsA = [NSArray arrayWithArray: domains];
672 [tableView reloadRowsAtIndexPaths: @[indexPath] withRowAnimation: UITableViewRowAnimationAutomatic];
673 }
674 else
675 {
676 if (cell.tag == kTag_AddBrowse )
677 {
678 CNDomainBrowserViewController *c = _browseController;
679 c.title = LocalizedStringFromMyBundle(@"_bonjour.browse.name", nil);
680 c.clearsSelectionOnViewWillAppear = NO;
681 c.modalPresentationStyle = UIModalPresentationFormSheet;
682 UINavigationController * nv = [[UINavigationController alloc] initWithRootViewController: c];
683 [self presentViewController: nv animated: YES completion: nil];
684 }
685 else if (cell.tag == kTag_AddManual )
686 {
687 CNManualDomainViewController * c = [[CNManualDomainViewController alloc] initWithStyle: UITableViewStyleGrouped];
688 c.delegate = self;
689 c.modalPresentationStyle = UIModalPresentationFormSheet;
690 UINavigationController * nv = [[UINavigationController alloc] initWithRootViewController: c];
691 [self presentViewController: nv animated: YES completion: nil];
692 }
693 }
694 }
695 [tableView deselectRowAtIndexPath: indexPath animated: YES];
696 }
697
698 #pragma mark - Commands
699
700 - (void)newPathSelected:(NSString *)fullPath
701 {
702 [CATransaction begin];
703 [CATransaction setCompletionBlock:^{
704 [self addBrowseDomain: fullPath];
705 }];
706 [self.navigationController popToViewController: self animated: YES];
707 [CATransaction commit];
708 }
709
710 @end