]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/DomainBrowser/iOS/CNDomainBrowserViewController.m
mDNSResponder-878.1.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / DomainBrowser / iOS / CNDomainBrowserViewController.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 "CNDomainBrowserViewController.h"
19 #import "_CNDomainBrowser.h"
20 #import "CNDomainBrowserPathUtils.h"
21 #import <AssertMacros.h>
22
23 #define LocalizedStringFromTableInMyBundle(key, table, comment) \
24 NSLocalizedStringFromTableInBundle(key, table, [NSBundle bundleForClass: [self class]], comment)
25
26
27 @interface CNTableViewController()
28 @property (copy) NSArray * pathArray;
29 @property (assign) NSInteger selectionIndex;
30 @end
31
32 @implementation CNTableViewController
33
34 - (instancetype)initWithStyle:(UITableViewStyle)style
35 {
36 if (self = [super initWithStyle: style])
37 {
38 _selectionIndex = NSNotFound;
39 _pathArray = [NSArray array];
40 }
41 return self;
42 }
43
44 @end
45
46 @interface CNDomainBrowserViewController ()
47
48 @property _CNDomainBrowser * bonjour;
49
50 @property (strong) NSMutableDictionary * instanceInfoStrings;
51 @property (strong) NSMutableDictionary * instanceStatusViews;
52
53 @end
54
55 @implementation CNDomainBrowserViewController
56
57 - (instancetype)initWithStyle:(UITableViewStyle)style
58 {
59 if (self = [super initWithStyle: style])
60 {
61 [self commonInit];
62 }
63 return(self);
64 }
65
66 - (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
67 {
68 if (self = [super initWithNibName: nibNameOrNil bundle: nibBundleOrNil])
69 {
70 [self commonInit];
71 }
72 return(self);
73 }
74
75 - (nullable instancetype)initWithCoder:(NSCoder *)coder
76 {
77 if (self = [super initWithCoder: coder])
78 {
79 [self commonInit];
80 }
81 return(self);
82 }
83
84 - (void)commonInit
85 {
86 self.bonjour = [[_CNDomainBrowser alloc] initWithDelegate: (id<_CNDomainBrowserDelegate>)self];
87 self.bonjour.browseRegistration = _browseRegistration;
88 self.bonjour.ignoreLocal = _ignoreLocal;
89 self.instanceInfoStrings = [NSMutableDictionary dictionary];
90 self.instanceStatusViews = [NSMutableDictionary dictionary];
91 }
92
93 - (void)viewWillAppear:(BOOL)animated
94 {
95 [super viewWillAppear: animated];
96 NSArray * pathArray = DNSDomainToDomainPath(_selectedDNSDomain);
97 if ((self.isMovingToParentViewController || self.isBeingPresented) && (pathArray.count > 1))
98 {
99 [self updateUIToDomainPathArray: pathArray];
100 }
101 }
102
103 - (void)viewDidLoad
104 {
105 [super viewDidLoad];
106
107 self.tableView.allowsMultipleSelectionDuringEditing = NO;
108 self.tableView.dataSource = (id<UITableViewDataSource>)self;
109 self.tableView.delegate = (id<UITableViewDelegate>)self;
110
111 self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: LocalizedStringFromTableInMyBundle(@"_dnsBrowser.browsedomains.cancel", @"DomainBrowser", nil)
112 style: UIBarButtonItemStylePlain
113 target: self
114 action: @selector(cancelAction:)];
115
116 }
117
118 - (void)updateUIToDomainPathArray:(NSArray *)newPathArray
119 {
120 if (newPathArray.count > 1)
121 {
122 CNTableViewController * controller = nil;
123 NSMutableArray * newSubPathArray = [NSMutableArray array];
124 for (NSString * nextPathComponent in newPathArray)
125 {
126 BOOL animate = NO;//(newPathArray.count == ++count);
127 controller = [self pushNewBrowseController: newSubPathArray.lastObject animated: animate];
128 controller.pathArray = newSubPathArray;
129 [newSubPathArray addObject: nextPathComponent];
130 }
131 }
132 }
133
134 - (IBAction)cancelAction:(id)sender
135 {
136 (void)sender; // Unused
137 [self.navigationController dismissViewControllerAnimated: YES completion: nil];
138 }
139
140 - (CNTableViewController *)pushNewBrowseController:(NSString *)title animated:(BOOL)animated
141 {
142 CNTableViewController *tvc = [[CNTableViewController alloc] initWithStyle: self.tableView.style];
143 tvc.title = title;
144 tvc.clearsSelectionOnViewWillAppear = NO;
145 tvc.tableView.dataSource = (id<UITableViewDataSource>)self;
146 tvc.tableView.delegate = (id<UITableViewDelegate>)self;
147 [self.navigationController pushViewController: tvc animated: animated];
148 return(tvc);
149 }
150
151 - (CNTableViewController *)controllerForTableView:(UITableView *)tableView
152 {
153 CNTableViewController * result = nil;
154
155 for (CNTableViewController * next in self.navigationController.viewControllers)
156 {
157 if ([next isKindOfClass: [CNTableViewController class]] && next.tableView == tableView)
158 {
159 result = next;
160 break;
161 }
162 }
163
164 return(result);
165 }
166
167 - (NSArray *)selectedPathArrayForTableView:(UITableView *)tableView includeSelectedRow:(BOOL)includeSelection
168 {
169 NSMutableArray * pathArray = [NSMutableArray array];
170 CNTableViewController * controller = [self controllerForTableView: tableView];
171
172 [pathArray addObjectsFromArray: controller.pathArray];
173
174 if (includeSelection && controller.selectionIndex != NSNotFound)
175 {
176 NSArray * rowArray = [[self.bonjour subDomainsAtDomainPath: pathArray] sortedArrayUsingComparator: ^(id obj1, id obj2) {
177 return (NSComparisonResult)[ obj1[_CNSubDomainKey_subPath] compare: obj2[_CNSubDomainKey_subPath]];
178 }];
179 if (controller.selectionIndex < (NSInteger)rowArray.count)
180 {
181 [pathArray addObject: rowArray[controller.selectionIndex][_CNSubDomainKey_subPath]];
182 }
183 }
184
185 return(pathArray);
186 }
187
188 - (void)plusButtonPressed:(UIControl *)button withEvent:(UIEvent *)event
189 {
190 UITableView * tableView = ((UITableViewController *)self.navigationController.topViewController).tableView;
191 NSIndexPath * indexPath = [tableView indexPathForRowAtPoint: [[[event touchesForView: button] anyObject] locationInView: tableView]];
192 if (indexPath != nil && self.delegate)
193 {
194 [self controllerForTableView: tableView].selectionIndex = indexPath.row;
195 NSArray * pathArray = [self selectedPathArrayForTableView: ((CNTableViewController *)self.navigationController.topViewController).tableView includeSelectedRow: YES];
196 _selectedDNSDomain = DomainPathToDNSDomain(pathArray);
197 [self.navigationController dismissViewControllerAnimated: YES completion: ^{
198 if ([self.delegate respondsToSelector: @selector(domainBrowserDomainSelected:)])
199 {
200 [self.delegate domainBrowserDomainSelected: _selectedDNSDomain];
201 }
202 }];
203 }
204 }
205
206 #pragma mark - Public Methods
207
208 - (void)setIgnoreLocal:(BOOL)ignoreLocal
209 {
210 _ignoreLocal = ignoreLocal;
211 self.bonjour.ignoreLocal = _ignoreLocal;
212 }
213
214 - (void)setBrowseRegistration:(BOOL)browseRegistration
215 {
216 _browseRegistration = browseRegistration;
217 self.bonjour.browseRegistration = _browseRegistration;
218 }
219
220 - (NSString *)defaultDNSDomain
221 {
222 return(DomainPathToDNSDomain(self.bonjour.defaultDomainPath));
223 }
224
225 - (NSArray *)flattenedDNSDomains
226 {
227 return(self.bonjour.flattenedDNSDomains);
228 }
229
230 - (void)startBrowse
231 {
232 [self.bonjour startBrowser];
233 }
234
235 - (void)stopBrowse
236 {
237 [self.bonjour stopBrowser];
238 }
239
240 - (BOOL)isBrowsing
241 {
242 return(self.bonjour.isBrowsing);
243 }
244
245 #pragma mark - TableView Delegates
246
247 - (CGFloat)tableView:(UITableView *)tableView estimatedHeightForRowAtIndexPath:(NSIndexPath *)indexPath
248 {
249 (void)tableView; // Unused
250 (void)indexPath; // Unused
251 return UITableViewAutomaticDimension;
252 }
253
254 - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
255 {
256 (void)tableView; // Unused
257 return(1);
258 }
259
260 - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
261 {
262 (void)section; // Unused
263 return([self.bonjour subDomainsAtDomainPath: [self selectedPathArrayForTableView: tableView includeSelectedRow: NO]].count);
264 }
265
266 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
267 {
268 UITableViewCell *cell = nil;
269
270 static NSString *MyIdentifier = @"browse_cell_id";
271 cell = [tableView dequeueReusableCellWithIdentifier: MyIdentifier];
272 if (!cell)
273 {
274 cell = [[UITableViewCell alloc] initWithStyle: UITableViewCellStyleDefault reuseIdentifier: MyIdentifier];
275 }
276
277 // Get the name
278 NSMutableArray * pathArray = [NSMutableArray arrayWithArray: [self selectedPathArrayForTableView: tableView includeSelectedRow: NO]];
279 NSArray * rowArray = [[self.bonjour subDomainsAtDomainPath: pathArray] sortedArrayUsingComparator: ^(id obj1, id obj2) {
280 return (NSComparisonResult)[ obj1[_CNSubDomainKey_subPath] compare: obj2[_CNSubDomainKey_subPath]];
281 }];
282 if (indexPath.row < (NSInteger)rowArray.count)
283 {
284 NSDictionary * item = [rowArray objectAtIndex: indexPath.row];
285 NSString *val = item[_CNSubDomainKey_subPath];
286 cell.textLabel.text = val;
287
288 // Set selection
289 BOOL selected = ([self controllerForTableView: tableView].selectionIndex == indexPath.row);
290 if (selected) [tableView selectRowAtIndexPath: indexPath animated: NO scrollPosition: UITableViewScrollPositionNone];
291
292 // Make Default domain bold
293 if ([item[_CNSubDomainKey_defaultFlag] boolValue]) cell.textLabel.font = [UIFont boldSystemFontOfSize: [UIFont labelFontSize]];
294 else cell.textLabel.font = nil;
295
296 // See if it's a leaf
297 [pathArray addObject: val];
298 cell.accessoryType = [self.bonjour subDomainsAtDomainPath: pathArray].count ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
299
300 // Add the "+" button
301 UIButton * plus = [UIButton buttonWithType: UIButtonTypeContactAdd];
302 [plus addTarget: self action: @selector(plusButtonPressed:withEvent:) forControlEvents: UIControlEventTouchUpInside];
303 plus.userInteractionEnabled = YES;
304 [cell.contentView addSubview: plus];
305
306 plus.translatesAutoresizingMaskIntoConstraints = NO;
307 [plus.widthAnchor constraintEqualToConstant: plus.frame.size.width].active = YES;
308 [plus.heightAnchor constraintEqualToConstant: plus.frame.size.height].active = YES;
309 [plus.centerYAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.centerYAnchor].active = YES;
310 [plus.trailingAnchor constraintEqualToAnchor: cell.layoutMarginsGuide.trailingAnchor constant: -20].active = YES;
311 }
312
313 return(cell);
314 }
315
316 - (nullable NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath
317 {
318 UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath];
319 return((cell.accessoryType == UITableViewCellAccessoryNone) ? nil : indexPath);
320 }
321
322 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
323 {
324 UITableViewCell * cell = [tableView cellForRowAtIndexPath: indexPath];
325 if (cell.accessoryType != UITableViewCellAccessoryNone)
326 {
327 // Push next
328 CNTableViewController * controller = [self controllerForTableView: tableView];
329 NSArray * lastpathArray = controller.pathArray;
330 controller.selectionIndex = indexPath.row;
331 NSString * title = cell.textLabel.text;
332 controller = [self pushNewBrowseController: title animated: YES];
333 controller.pathArray = [lastpathArray arrayByAddingObject: title];
334 }
335 [tableView deselectRowAtIndexPath: indexPath animated: YES];
336 }
337
338 #pragma mark - _CNDomainBrowser Delegates
339
340 - (void)bonjourBrowserDomainUpdate:(NSArray *)defaultDomainPath
341 {
342 _selectedDNSDomain = DomainPathToDNSDomain(defaultDomainPath);
343 [((UITableViewController *)self.navigationController.topViewController).tableView reloadData];
344 if ([self.delegate respondsToSelector: @selector(bonjourBrowserDomainUpdate:)])
345 {
346 [self.delegate bonjourBrowserDomainUpdate: _selectedDNSDomain];
347 }
348 }
349
350 @end