RSS

(root)/iphone/common : /source/BonjourSupport/DomainViewController.m (revision 100)

To get this branch, use:
bzr branch /browse/iphone/common
Line Revision Contents
1 46
/*
2
     File: DomainViewController.m
3
 Abstract:  View controller for the domain list.
4
 This object manages a NSNetServiceBrowser configured to look for Bonjour
5
domains.
6
 It has two arrays of NSString objects that are displayed in two sections of a
7
table view.
8
 When the service browser reports that it has discovered a domain, that domain
9
is added to the first array.
10
 When a domain goes away it is removed from the first array.
11
 It allows the user to add/remove their own domains from the second array, which
12
is displayed in the second section of the table.
13
 When an item in the table view is selected, the delegate is called with the
14
corresponding domain.
15
16
  Version: 2.8
17
 
18
 Disclaimer: IMPORTANT:  This Apple software is supplied to you by Apple
19
 Inc. ("Apple") in consideration of your agreement to the following
20
 terms, and your use, installation, modification or redistribution of
21
 this Apple software constitutes acceptance of these terms.  If you do
22
 not agree with these terms, please do not use, install, modify or
23
 redistribute this Apple software.
24
 
25
 In consideration of your agreement to abide by the following terms, and
26
 subject to these terms, Apple grants you a personal, non-exclusive
27
 license, under Apple's copyrights in this original Apple software (the
28
 "Apple Software"), to use, reproduce, modify and redistribute the Apple
29
 Software, with or without modifications, in source and/or binary forms;
30
 provided that if you redistribute the Apple Software in its entirety and
31
 without modifications, you must retain this notice and the following
32
 text and disclaimers in all such redistributions of the Apple Software.
33
 Neither the name, trademarks, service marks or logos of Apple Inc. may
34
 be used to endorse or promote products derived from the Apple Software
35
 without specific prior written permission from Apple.  Except as
36
 expressly stated in this notice, no other rights or licenses, express or
37
 implied, are granted by Apple herein, including but not limited to any
38
 patent rights that may be infringed by your derivative works or by other
39
 works in which the Apple Software may be incorporated.
40
 
41
 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE
42
 MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION
43
 THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS
44
 FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND
45
 OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
46
 
47
 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL
48
 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
49
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
50
 INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION,
51
 MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
52
 AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE),
53
 STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
54
 POSSIBILITY OF SUCH DAMAGE.
55
 
56
 Copyright (C) 2009 Apple Inc. All Rights Reserved.
57
 
58
 */
59
60
#import "DomainViewController.h"
61
62
#define kProgressIndicatorSize 20.0
63
64
@interface DomainViewController ()
65
@property(nonatomic, assign) BOOL showDisclosureIndicators;
66
@property(nonatomic, retain) NSMutableArray* domains;
67
@property(nonatomic, retain) NSMutableArray* customs;
68
@property(nonatomic, retain) NSString* customTitle;
69
@property(nonatomic, retain) NSString* addDomainTitle;
70
@property(nonatomic, retain) NSNetServiceBrowser* netServiceBrowser;
71
@property(nonatomic, assign) BOOL showCancelButton;
72
73
- (void)addButtons:(BOOL)editing;
74
- (void)addAction:(id)sender;
75
- (void)editAction:(id)sender;
76
@end
77
78
@implementation DomainViewController
79
80
@synthesize delegate = _delegate;
81
@synthesize showDisclosureIndicators = _showDisclosureIndicators;
82
@synthesize domains = _domains;
83
@synthesize customs = _customs;
84
@synthesize customTitle = _customTitle;
85
@synthesize addDomainTitle = _addDomainTitle;
86
@dynamic netServiceBrowser;
87
@synthesize showCancelButton = _showCancelButton;
88
89
// Initialization. BonjourBrowser invokes this during its initialization.
90
- (id)initWithTitle:(NSString*)title showDisclosureIndicators:(BOOL)show customsTitle:(NSString*)customsTitle customs:(NSMutableArray*)customs addDomainTitle:(NSString*)addDomainTitle showCancelButton:(BOOL)showCancelButton {
91
	if ((self = [super initWithStyle:UITableViewStylePlain])) {
92
		self.title = title;
93 94
		self.domains = [[NSMutableArray alloc] init];
94 46
		self.showDisclosureIndicators = show;
95
		self.customTitle = customsTitle;
96
		self.customs = customs ? customs : [NSMutableArray array];
97
		self.addDomainTitle = addDomainTitle;
98
		self.showCancelButton = showCancelButton;
99
		[self addButtons:self.tableView.editing];
100
	}
101
102
	return self;
103
}
104
105
// Stores newBrowser in the _netServiceBrowser instance variable. If _netServiceBrowser has already been set,
106
// this first sends it a -stop message before releasing it.
107
- (void)setNetServiceBrowser:(NSNetServiceBrowser*)newBrowser {
108
	[_netServiceBrowser stop];
109 94
110 46
	_netServiceBrowser = newBrowser;
111
}
112
113
114
- (NSNetServiceBrowser*)netServiceBrowser {
115
	return _netServiceBrowser;
116
}
117
118
119
- (void)addAddButton:(BOOL)right {
120
	// add + button as the nav bar's custom right view
121
	UIBarButtonItem *addButton = [[UIBarButtonItem alloc]
122
								  initWithBarButtonSystemItem:UIBarButtonSystemItemAdd target:self action:@selector(addAction:)];
123
	if (right) self.navigationItem.rightBarButtonItem = addButton;
124
	else self.navigationItem.leftBarButtonItem = addButton;
125
}
126
127
- (void)addButtons:(BOOL)editing {
128
	if (editing) {
129
		// Add the "done" button to the navigation bar
130
		UIBarButtonItem *doneButton = [[UIBarButtonItem alloc]
131
									   initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneAction:)];
132
		
133
		self.navigationItem.leftBarButtonItem = doneButton;
134
135
		[self addAddButton:YES];
136
	} else {
137
		if ([self.customs count]) {
138
			// Add the "edit" button to the navigation bar
139
			UIBarButtonItem *editButton = [[UIBarButtonItem alloc]
140
										   initWithBarButtonSystemItem:UIBarButtonSystemItemEdit target:self action:@selector(editAction:)];
141
			
142
			self.navigationItem.leftBarButtonItem = editButton;
143
		} else {
144
			[self addAddButton:NO];
145
		}
146
		
147
		if (self.showCancelButton) {
148
			// add Cancel button as the nav bar's custom right view
149
			UIBarButtonItem *addButton = [[UIBarButtonItem alloc]
150
										  initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAction)];
151
			self.navigationItem.rightBarButtonItem = addButton;
152
		} else {
153
			self.navigationItem.rightBarButtonItem = nil;
154
		}
155
	}
156
}
157
158
- (BOOL)commonSetup {
159 94
	self.netServiceBrowser = [[NSNetServiceBrowser alloc] init];
160 46
	if(!self.netServiceBrowser) {
161
		return NO;
162
	}
163
	
164 94
	[self.netServiceBrowser setDelegate: self];
165 46
	return YES;
166
}
167
168
// A cover method to -[NSNetServiceBrowser searchForBrowsableDomains].
169
- (BOOL)searchForBrowsableDomains {
170
	if (![self commonSetup]) return NO;
171
	[self.netServiceBrowser searchForBrowsableDomains];
172
	return YES;
173
}
174
175
// A cover method to -[NSNetServiceBrowser searchForRegistrationDomains].
176
- (BOOL)searchForRegistrationDomains {
177
	if (![self commonSetup]) return NO;
178
	[self.netServiceBrowser searchForRegistrationDomains];	
179
	return YES;
180
}
181
182
183
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
184
	return 1 + ([self.customs count] ? 1 : 0);
185
}
186
187
188
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
189
	return [(section ? self.customs : self.domains) count];
190
}
191
192
193
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
194
	return section ? self.customTitle : @"Bonjour"; // Note that "Bonjour" is the proper name of the technology, therefore should not be localized
195
}
196
197
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
198
	UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:@"UITableViewCell"];
199
	if (cell == nil) {
200 94
		cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"UITableViewCell"];
201 46
	}
202
	
203
	// Set up the text for the cell
204
	cell.textLabel.text = [(indexPath.section ? self.customs : self.domains) objectAtIndex:indexPath.row];
205
	cell.textLabel.textColor = [UIColor blackColor];
206
	cell.accessoryType = self.showDisclosureIndicators ? UITableViewCellAccessoryDisclosureIndicator : UITableViewCellAccessoryNone;
207
	return cell;
208
}
209
210
211
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
212
	return indexPath.section && tableView.editing;
213
}
214
215
216
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
217
	[self.delegate domainViewController:self didSelectDomain:[(indexPath.section ? self.customs : self.domains) objectAtIndex:indexPath.row]];
218
}
219
220
221
- (void)updateUI {
222
	// Sort the domains by name, then modify the selection, as it may have moved
223
	[self.domains sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
224
	[self.tableView reloadData];
225
}
226
227
/*
228
    The 'domain' parameter passed to netServiceBrowser:didRemoveDomain:moreComing: and netServiceBrowser:didFindDomain:moreComing: may contain escaped characters. This function unescapes them before they are added to or removed from the list that is displayed to the user.
229
*/
230
- (NSString*) transmogrify:(NSString*)aString {
231
	
232
	NSString* tmp = [NSString stringWithString:aString];
233
	const char *ostr = [tmp UTF8String];
234
	const char *cstr = ostr;
235
	char *ptr = (char*) ostr;
236
	
237
	while (*cstr) {
238
		char c = *cstr++;
239
		if (c == '\\')
240
		{
241
			c = *cstr++;
242
			if (isdigit(cstr[-1]) && isdigit(cstr[0]) && isdigit(cstr[1]))
243
			{
244
				NSInteger v0 = cstr[-1] - '0';						// then interpret as three-digit decimal
245
				NSInteger v1 = cstr[ 0] - '0';
246
				NSInteger v2 = cstr[ 1] - '0';
247
				NSInteger val = v0 * 100 + v1 * 10 + v2;
248
				if (val <= 255) { c = (char)val; cstr += 2; }	// If valid three-digit decimal value, use it
249
			}
250
		}
251
		*ptr++ = c;
252
	}
253
	ptr--;
254
	*ptr = 0;
255
	return [NSString stringWithUTF8String:ostr];
256
}
257
258
259
- (void)netServiceBrowser:(NSNetServiceBrowser*)netServiceBrowser didRemoveDomain:(NSString*)domain moreComing:(BOOL)moreComing {
260
	[self.domains removeObject:[self transmogrify:domain]];
261
	
262
	// moreComing really means that there are no more messages in the queue from the Bonjour daemon, so we should update the UI.
263
	// When moreComing is set, we don't update the UI so that it doesn't 'flash'.
264
	if (!moreComing)
265
		[self updateUI];
266
}	
267
268
269
- (void)netServiceBrowser:(NSNetServiceBrowser*)netServiceBrowser didFindDomain:(NSString*)domain moreComing:(BOOL)moreComing {
270
	NSString* tmp = [self transmogrify:domain];
271
	if (![self.domains containsObject:tmp]) [self.domains addObject:tmp];
272
273
	// moreComing really means that there are no more messages in the queue from the Bonjour daemon, so we should update the UI.
274
	// When moreComing is set, we don't update the UI so that it doesn't 'flash'.
275
	if (!moreComing)
276
		[self updateUI];
277
}	
278
279
280
- (void)doneAction:(id)sender {
281
	[self.tableView setEditing:NO animated:YES];
282
	[self addButtons:self.tableView.editing];
283
}
284
285
286
- (void)editAction:(id)sender {
287
	[self.tableView setEditing:YES animated:YES];
288
	[self addButtons:self.tableView.editing];
289
}
290
291
292
- (IBAction)cancelAction {
293
	[self.delegate domainViewController:self didSelectDomain:nil];
294
}
295
296
297
- (void)addAction:(id)sender {
298
	SimpleEditViewController* sevc = [[SimpleEditViewController alloc] initWithTitle:self.addDomainTitle currentText:nil];
299
	[sevc setDelegate:self];
300
	UINavigationController* nc = [[UINavigationController alloc] initWithRootViewController:sevc];
301 94
302 46
	[self.navigationController presentModalViewController:nc animated:YES];
303 94
304 46
}
305
306
307
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
308
	assert(editingStyle == UITableViewCellEditingStyleDelete);
309
	assert(indexPath.section == 1);
310
	[self.customs removeObjectAtIndex:indexPath.row];
311
	if (![self.customs count]) {
312
		[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationRight];
313
	} else {
314
		[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];
315
	}
316
	[self addButtons:self.tableView.editing];
317
}
318
319
320
- (void) simpleEditViewController:(SimpleEditViewController*)sevc didGetText:(NSString*)text {
321
	[self.navigationController dismissModalViewControllerAnimated:YES];
322
323
	if (![text length])
324
		return;
325
	
326
	if (![self.customs containsObject:text]) {
327
		[self.customs addObject:text];
328
		[self.customs sortUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
329
	}
330
	
331
	[self addButtons:self.tableView.editing];
332
	[self.tableView reloadData];
333
	NSUInteger ints[2] = {1,[self.customs indexOfObject:text]};
334
	NSIndexPath* indexPath = [NSIndexPath indexPathWithIndexes:ints length:2];
335
	[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionNone animated:YES];
336
}
337
338
339 94
- (void)dealloc
340
{
341 46
	
342
}
343
344
@end

Loggerhead 1.17 is a web-based interface for Bazaar branches