FreeRDP
Bookmark.m
1 /*
2  Bookmark model abstraction
3 
4  Copyright 2013 Thincast Technologies GmbH, Author: Dorian Johnson
5 
6  This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
7  If a copy of the MPL was not distributed with this file, You can obtain one at
8  http://mozilla.org/MPL/2.0/.
9  */
10 
11 #import "Bookmark.h"
12 #import "TSXAdditions.h"
13 #import "Utils.h"
14 
15 #import "GlobalDefaults.h"
16 
17 @interface ComputerBookmark (Private)
18 - (void)willChangeValueForKeyPath:(NSString *)keyPath;
19 - (void)didChangeValueForKeyPath:(NSString *)keyPath;
20 @end
21 
22 @implementation ComputerBookmark
23 
24 @synthesize parent = _parent, uuid = _uuid, label = _label, image = _image;
25 @synthesize params = _connection_params, conntectedViaWLAN = _connected_via_wlan;
26 
27 - (id)init
28 {
29  if (!(self = [super init]))
30  return nil;
31 
32  _uuid = [[NSString stringWithUUID] retain];
33  _label = @"";
34  _connected_via_wlan = NO;
35  return self;
36 }
37 
38 // Designated initializer.
39 - (id)initWithConnectionParameters:(ConnectionParams *)params
40 {
41  if (!(self = [self init]))
42  return nil;
43 
44  _connection_params = [params copy];
45  _connected_via_wlan = NO;
46  return self;
47 }
48 
49 - (id)initWithCoder:(NSCoder *)decoder
50 {
51  if (!(self = [self init]))
52  return nil;
53 
54  if (![decoder allowsKeyedCoding])
55  [NSException raise:NSInvalidArgumentException format:@"coder must support keyed archiving"];
56 
57  if ([decoder containsValueForKey:@"uuid"])
58  {
59  [_uuid release];
60  _uuid = [[decoder decodeObjectForKey:@"uuid"] retain];
61  }
62 
63  if ([decoder containsValueForKey:@"label"])
64  [self setLabel:[decoder decodeObjectForKey:@"label"]];
65 
66  if ([decoder containsValueForKey:@"connectionParams"])
67  {
68  [_connection_params release];
69  _connection_params = [[decoder decodeObjectForKey:@"connectionParams"] retain];
70  }
71 
72  return self;
73 }
74 
75 - (id)initWithBaseDefaultParameters
76 {
77  return [self initWithConnectionParameters:[[[ConnectionParams alloc]
78  initWithBaseDefaultParameters] autorelease]];
79 }
80 
81 - (id)copy
82 {
83  ComputerBookmark *copy = [[[self class] alloc] init];
84  [copy setLabel:[self label]];
85  copy->_connection_params = [_connection_params copy];
86  return copy;
87 }
88 
89 - (id)copyWithUUID
90 {
91  ComputerBookmark *copy = [self copy];
92  copy->_uuid = [[self uuid] copy];
93  return copy;
94 }
95 
96 - (void)encodeWithCoder:(NSCoder *)coder
97 {
98  if (![coder allowsKeyedCoding])
99  [NSException raise:NSInvalidArgumentException format:@"coder must support keyed archiving"];
100 
101  [coder encodeObject:_uuid forKey:@"uuid"];
102  [coder encodeObject:_label forKey:@"label"];
103  [coder encodeObject:_connection_params forKey:@"connectionParams"];
104 }
105 
106 - (void)dealloc
107 {
108  _parent = nil;
109  [_label release];
110  _label = nil;
111  [_uuid release];
112  _uuid = nil;
113  [_connection_params release];
114  _connection_params = nil;
115  [super dealloc];
116 }
117 
118 - (UIImage *)image
119 {
120  return nil;
121 }
122 
123 - (BOOL)isEqual:(id)object
124 {
125  return [object respondsToSelector:@selector(uuid)] && [[object uuid] isEqual:_uuid];
126 }
127 
128 - (NSString *)description
129 {
130  return ([self label] != nil) ? [self label] : _uuid;
131 }
132 
133 - (BOOL)validateValue:(id *)val forKey:(NSString *)key error:(NSError **)error
134 {
135  NSString *string_value = *val;
136 
137  if ([key isEqualToString:@"label"])
138  {
139  if (![[string_value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]
140  length])
141  {
142  if (error)
143  *error = [NSError
144  errorWithDomain:@""
145  code:NSKeyValueValidationError
146  userInfo:
147  [NSDictionary
148  dictionaryWithObjectsAndKeys:
149  NSLocalizedString(
150  @"Connection labels cannot be blank",
151  @"Bookmark data validation: label blank title."),
152  NSLocalizedDescriptionKey,
153  NSLocalizedString(
154  @"Please enter the short description of this Connection "
155  @"that will appear in the Connection list.",
156  @"Bookmark data validation: label blank message."),
157  NSLocalizedRecoverySuggestionErrorKey, nil]];
158  return NO;
159  }
160  }
161 
162  return YES;
163 }
164 
165 - (BOOL)validateValue:(id *)val forKeyPath:(NSString *)keyPath error:(NSError **)error
166 {
167  // Could be used to validate params.hostname, params.password, params.port, etc.
168  return [super validateValue:val forKeyPath:keyPath error:error];
169 }
170 
171 - (BOOL)isDeletable
172 {
173  return YES;
174 }
175 - (BOOL)isMovable
176 {
177  return YES;
178 }
179 - (BOOL)isRenamable
180 {
181  return YES;
182 }
183 - (BOOL)hasImmutableHost
184 {
185  return NO;
186 }
187 
188 #pragma mark Custom KVC
189 
190 - (void)setValue:(id)value forKeyPath:(NSString *)keyPath
191 {
192  if ([keyPath isEqualToString:@"params.resolution"])
193  {
194  int width, height;
195  TSXScreenOptions type;
196  if (ScanScreenResolution(value, &width, &height, &type))
197  {
198  [_connection_params willChangeValueForKey:@"resolution"];
199  [[self params] setInt:type forKey:@"screen_resolution_type"];
200 
201  if (type == TSXScreenOptionFixed)
202  {
203  [[self params] setInt:width forKey:@"width"];
204  [[self params] setInt:height forKey:@"height"];
205  }
206  [_connection_params didChangeValueForKey:@"resolution"];
207  }
208  else
209  [NSException raise:NSInvalidArgumentException
210  format:@"%s got invalid screen resolution '%@'", __func__, value];
211  }
212  else
213  {
214  [self willChangeValueForKeyPath:keyPath];
215  [super setValue:value forKeyPath:keyPath];
216  [self didChangeValueForKeyPath:keyPath];
217  }
218 }
219 
220 - (id)valueForKeyPath:(NSString *)keyPath
221 {
222  if ([keyPath isEqualToString:@"params.resolution"])
223  return ScreenResolutionDescription([[self params] intForKey:@"screen_resolution_type"],
224  [[self params] intForKey:@"width"],
225  [[self params] intForKey:@"height"]);
226 
227  return [super valueForKeyPath:keyPath];
228 }
229 
230 - (void)observeValueForKeyPath:(NSString *)keyPath
231  ofObject:(id)object
232  change:(NSDictionary *)change
233  context:(void *)context
234 {
235  if ([[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue])
236  [self willChangeValueForKeyPath:keyPath];
237  else
238  [self didChangeValueForKeyPath:keyPath];
239 }
240 
241 - (NSDictionary *)targetForChangeNotificationForKeyPath:(NSString *)keyPath
242 {
243  NSString *changed_key = keyPath;
244  NSObject *changed_object = self;
245 
246  if ([keyPath rangeOfString:@"params."].location == 0)
247  {
248  changed_key = [keyPath substringFromIndex:[@"params." length]];
249  changed_object = _connection_params;
250  }
251 
252  return [NSDictionary
253  dictionaryWithObjectsAndKeys:changed_key, @"key", changed_object, @"object", nil];
254 }
255 
256 - (void)willChangeValueForKeyPath:(NSString *)keyPath
257 {
258  NSDictionary *target = [self targetForChangeNotificationForKeyPath:keyPath];
259  [[target objectForKey:@"object"] willChangeValueForKey:[target objectForKey:@"key"]];
260 }
261 
262 - (void)didChangeValueForKeyPath:(NSString *)keyPath
263 {
264  NSDictionary *target = [self targetForChangeNotificationForKeyPath:keyPath];
265  [[target objectForKey:@"object"] didChangeValueForKey:[target objectForKey:@"key"]];
266 }
267 
268 - (ConnectionParams *)copyMarkedParams
269 {
270  ConnectionParams *param_copy = [[self params] copy];
271  [param_copy setValue:[self uuid] forKey:@"_bookmark_uuid"];
272  return param_copy;
273 }
274 
275 #pragma mark No children
276 - (NSUInteger)numberOfChildren
277 {
278  return 0;
279 }
280 - (NSUInteger)numberOfDescendants
281 {
282  return 1;
283 }
284 - (BookmarkBase *)childAtIndex:(NSUInteger)index
285 {
286  return nil;
287 }
288 - (NSUInteger)indexOfChild:(BookmarkBase *)child
289 {
290  return 0;
291 }
292 - (void)removeChild:(BookmarkBase *)child
293 {
294 }
295 - (void)addChild:(BookmarkBase *)child
296 {
297 }
298 - (void)addChild:(BookmarkBase *)child afterExistingChild:(BookmarkBase *)existingChild
299 {
300 }
301 - (void)addChild:(BookmarkBase *)child atIndex:(NSInteger)index
302 {
303 }
304 - (BOOL)hasDescendant:(BookmarkBase *)needle
305 {
306  return NO;
307 }
308 - (BOOL)canContainChildren
309 {
310  return NO;
311 }
312 @end