2013-02-14 17:59:12 +04:00
|
|
|
/*
|
|
|
|
Bookmark model abstraction
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-12-04 14:37:57 +04:00
|
|
|
Copyright 2013 Thincast Technologies GmbH, Author: Dorian Johnson
|
2013-02-14 17:59:12 +04:00
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
|
|
If a copy of the MPL was not distributed with this file, You can obtain one at
|
|
|
|
http://mozilla.org/MPL/2.0/.
|
|
|
|
*/
|
2013-02-14 17:59:12 +04:00
|
|
|
|
|
|
|
#import "Bookmark.h"
|
|
|
|
#import "TSXAdditions.h"
|
|
|
|
#import "Utils.h"
|
|
|
|
|
|
|
|
#import "GlobalDefaults.h"
|
|
|
|
|
|
|
|
@interface ComputerBookmark (Private)
|
|
|
|
- (void)willChangeValueForKeyPath:(NSString *)keyPath;
|
|
|
|
- (void)didChangeValueForKeyPath:(NSString *)keyPath;
|
|
|
|
@end
|
|
|
|
|
|
|
|
@implementation ComputerBookmark
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
@synthesize parent = _parent, uuid = _uuid, label = _label, image = _image;
|
|
|
|
@synthesize params = _connection_params, conntectedViaWLAN = _connected_via_wlan;
|
2013-02-14 17:59:12 +04:00
|
|
|
|
|
|
|
- (id)init
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
if (!(self = [super init]))
|
2013-02-14 17:59:12 +04:00
|
|
|
return nil;
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
_uuid = [[NSString stringWithUUID] retain];
|
|
|
|
_label = @"";
|
2019-11-06 17:24:51 +03:00
|
|
|
_connected_via_wlan = NO;
|
|
|
|
return self;
|
2013-02-14 17:59:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Designated initializer.
|
2019-11-06 17:24:51 +03:00
|
|
|
- (id)initWithConnectionParameters:(ConnectionParams *)params
|
2013-02-14 17:59:12 +04:00
|
|
|
{
|
2013-04-05 12:46:28 +04:00
|
|
|
if (!(self = [self init]))
|
2013-02-14 17:59:12 +04:00
|
|
|
return nil;
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
_connection_params = [params copy];
|
2019-11-06 17:24:51 +03:00
|
|
|
_connected_via_wlan = NO;
|
2013-02-14 17:59:12 +04:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initWithCoder:(NSCoder *)decoder
|
|
|
|
{
|
|
|
|
if (!(self = [self init]))
|
|
|
|
return nil;
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
if (![decoder allowsKeyedCoding])
|
|
|
|
[NSException raise:NSInvalidArgumentException format:@"coder must support keyed archiving"];
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
if ([decoder containsValueForKey:@"uuid"])
|
|
|
|
{
|
|
|
|
[_uuid release];
|
2019-11-06 17:24:51 +03:00
|
|
|
_uuid = [[decoder decodeObjectForKey:@"uuid"] retain];
|
2013-02-14 17:59:12 +04:00
|
|
|
}
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
if ([decoder containsValueForKey:@"label"])
|
|
|
|
[self setLabel:[decoder decodeObjectForKey:@"label"]];
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
if ([decoder containsValueForKey:@"connectionParams"])
|
|
|
|
{
|
|
|
|
[_connection_params release];
|
|
|
|
_connection_params = [[decoder decodeObjectForKey:@"connectionParams"] retain];
|
|
|
|
}
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
return self;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)initWithBaseDefaultParameters
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
return [self initWithConnectionParameters:[[[ConnectionParams alloc]
|
|
|
|
initWithBaseDefaultParameters] autorelease]];
|
2013-02-14 17:59:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
- (id)copy
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
ComputerBookmark *copy = [[[self class] alloc] init];
|
2013-02-14 17:59:12 +04:00
|
|
|
[copy setLabel:[self label]];
|
|
|
|
copy->_connection_params = [_connection_params copy];
|
|
|
|
return copy;
|
|
|
|
}
|
|
|
|
|
2013-04-03 11:36:55 +04:00
|
|
|
- (id)copyWithUUID
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
ComputerBookmark *copy = [self copy];
|
|
|
|
copy->_uuid = [[self uuid] copy];
|
|
|
|
return copy;
|
2013-04-03 11:36:55 +04:00
|
|
|
}
|
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
- (void)encodeWithCoder:(NSCoder *)coder
|
|
|
|
{
|
|
|
|
if (![coder allowsKeyedCoding])
|
|
|
|
[NSException raise:NSInvalidArgumentException format:@"coder must support keyed archiving"];
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
[coder encodeObject:_uuid forKey:@"uuid"];
|
|
|
|
[coder encodeObject:_label forKey:@"label"];
|
|
|
|
[coder encodeObject:_connection_params forKey:@"connectionParams"];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)dealloc
|
2019-11-06 17:24:51 +03:00
|
|
|
{
|
2013-02-14 17:59:12 +04:00
|
|
|
_parent = nil;
|
2019-11-06 17:24:51 +03:00
|
|
|
[_label release];
|
|
|
|
_label = nil;
|
|
|
|
[_uuid release];
|
|
|
|
_uuid = nil;
|
|
|
|
[_connection_params release];
|
|
|
|
_connection_params = nil;
|
2013-02-14 17:59:12 +04:00
|
|
|
[super dealloc];
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
- (UIImage *)image
|
2013-02-14 17:59:12 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
return nil;
|
2013-02-14 17:59:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)isEqual:(id)object
|
|
|
|
{
|
|
|
|
return [object respondsToSelector:@selector(uuid)] && [[object uuid] isEqual:_uuid];
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
- (NSString *)description
|
2013-02-14 17:59:12 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
return ([self label] != nil) ? [self label] : _uuid;
|
2013-02-14 17:59:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)validateValue:(id *)val forKey:(NSString *)key error:(NSError **)error
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
NSString *string_value = *val;
|
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
if ([key isEqualToString:@"label"])
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
if (![[string_value stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]
|
|
|
|
length])
|
2013-02-14 17:59:12 +04:00
|
|
|
{
|
|
|
|
if (error)
|
2019-11-06 17:24:51 +03:00
|
|
|
*error = [NSError
|
|
|
|
errorWithDomain:@""
|
|
|
|
code:NSKeyValueValidationError
|
|
|
|
userInfo:
|
|
|
|
[NSDictionary
|
|
|
|
dictionaryWithObjectsAndKeys:
|
|
|
|
NSLocalizedString(
|
|
|
|
@"Connection labels cannot be blank",
|
|
|
|
@"Bookmark data validation: label blank title."),
|
|
|
|
NSLocalizedDescriptionKey,
|
|
|
|
NSLocalizedString(
|
|
|
|
@"Please enter the short description of this Connection "
|
|
|
|
@"that will appear in the Connection list.",
|
|
|
|
@"Bookmark data validation: label blank message."),
|
|
|
|
NSLocalizedRecoverySuggestionErrorKey, nil]];
|
2013-02-14 17:59:12 +04:00
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
}
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
|
|
|
|
- (BOOL)validateValue:(id *)val forKeyPath:(NSString *)keyPath error:(NSError **)error
|
|
|
|
{
|
|
|
|
// Could be used to validate params.hostname, params.password, params.port, etc.
|
|
|
|
return [super validateValue:val forKeyPath:keyPath error:error];
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
- (BOOL)isDeletable
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
- (BOOL)isMovable
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
- (BOOL)isRenamable
|
|
|
|
{
|
|
|
|
return YES;
|
|
|
|
}
|
|
|
|
- (BOOL)hasImmutableHost
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
2013-02-14 17:59:12 +04:00
|
|
|
|
|
|
|
#pragma mark Custom KVC
|
|
|
|
|
|
|
|
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath
|
|
|
|
{
|
|
|
|
if ([keyPath isEqualToString:@"params.resolution"])
|
|
|
|
{
|
|
|
|
int width, height;
|
|
|
|
TSXScreenOptions type;
|
|
|
|
if (ScanScreenResolution(value, &width, &height, &type))
|
|
|
|
{
|
|
|
|
[_connection_params willChangeValueForKey:@"resolution"];
|
|
|
|
[[self params] setInt:type forKey:@"screen_resolution_type"];
|
2019-11-06 17:24:51 +03:00
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
if (type == TSXScreenOptionFixed)
|
|
|
|
{
|
|
|
|
[[self params] setInt:width forKey:@"width"];
|
|
|
|
[[self params] setInt:height forKey:@"height"];
|
|
|
|
}
|
|
|
|
[_connection_params didChangeValueForKey:@"resolution"];
|
|
|
|
}
|
|
|
|
else
|
2019-11-06 17:24:51 +03:00
|
|
|
[NSException raise:NSInvalidArgumentException
|
|
|
|
format:@"%s got invalid screen resolution '%@'", __func__, value];
|
2013-02-14 17:59:12 +04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
[self willChangeValueForKeyPath:keyPath];
|
2019-11-06 17:24:51 +03:00
|
|
|
[super setValue:value forKeyPath:keyPath];
|
2013-02-14 17:59:12 +04:00
|
|
|
[self didChangeValueForKeyPath:keyPath];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
- (id)valueForKeyPath:(NSString *)keyPath
|
|
|
|
{
|
|
|
|
if ([keyPath isEqualToString:@"params.resolution"])
|
2019-11-06 17:24:51 +03:00
|
|
|
return ScreenResolutionDescription([[self params] intForKey:@"screen_resolution_type"],
|
|
|
|
[[self params] intForKey:@"width"],
|
|
|
|
[[self params] intForKey:@"height"]);
|
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
return [super valueForKeyPath:keyPath];
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath
|
|
|
|
ofObject:(id)object
|
|
|
|
change:(NSDictionary *)change
|
|
|
|
context:(void *)context
|
|
|
|
{
|
2013-02-14 17:59:12 +04:00
|
|
|
if ([[change objectForKey:NSKeyValueChangeNotificationIsPriorKey] boolValue])
|
|
|
|
[self willChangeValueForKeyPath:keyPath];
|
|
|
|
else
|
2019-11-06 17:24:51 +03:00
|
|
|
[self didChangeValueForKeyPath:keyPath];
|
2013-02-14 17:59:12 +04:00
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
- (NSDictionary *)targetForChangeNotificationForKeyPath:(NSString *)keyPath
|
2013-02-14 17:59:12 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
NSString *changed_key = keyPath;
|
|
|
|
NSObject *changed_object = self;
|
|
|
|
|
2013-02-14 17:59:12 +04:00
|
|
|
if ([keyPath rangeOfString:@"params."].location == 0)
|
|
|
|
{
|
|
|
|
changed_key = [keyPath substringFromIndex:[@"params." length]];
|
|
|
|
changed_object = _connection_params;
|
|
|
|
}
|
2019-11-06 17:24:51 +03:00
|
|
|
|
|
|
|
return [NSDictionary
|
|
|
|
dictionaryWithObjectsAndKeys:changed_key, @"key", changed_object, @"object", nil];
|
2013-02-14 17:59:12 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
- (void)willChangeValueForKeyPath:(NSString *)keyPath
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
NSDictionary *target = [self targetForChangeNotificationForKeyPath:keyPath];
|
2013-02-14 17:59:12 +04:00
|
|
|
[[target objectForKey:@"object"] willChangeValueForKey:[target objectForKey:@"key"]];
|
|
|
|
}
|
|
|
|
|
|
|
|
- (void)didChangeValueForKeyPath:(NSString *)keyPath
|
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
NSDictionary *target = [self targetForChangeNotificationForKeyPath:keyPath];
|
2013-02-14 17:59:12 +04:00
|
|
|
[[target objectForKey:@"object"] didChangeValueForKey:[target objectForKey:@"key"]];
|
|
|
|
}
|
|
|
|
|
2019-11-06 17:24:51 +03:00
|
|
|
- (ConnectionParams *)copyMarkedParams
|
2013-02-14 17:59:12 +04:00
|
|
|
{
|
2019-11-06 17:24:51 +03:00
|
|
|
ConnectionParams *param_copy = [[self params] copy];
|
2013-02-14 17:59:12 +04:00
|
|
|
[param_copy setValue:[self uuid] forKey:@"_bookmark_uuid"];
|
|
|
|
return param_copy;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark No children
|
2019-11-06 17:24:51 +03:00
|
|
|
- (NSUInteger)numberOfChildren
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
- (NSUInteger)numberOfDescendants
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
- (BookmarkBase *)childAtIndex:(NSUInteger)index
|
|
|
|
{
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
- (NSUInteger)indexOfChild:(BookmarkBase *)child
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
- (void)removeChild:(BookmarkBase *)child
|
|
|
|
{
|
|
|
|
}
|
|
|
|
- (void)addChild:(BookmarkBase *)child
|
|
|
|
{
|
|
|
|
}
|
|
|
|
- (void)addChild:(BookmarkBase *)child afterExistingChild:(BookmarkBase *)existingChild
|
|
|
|
{
|
|
|
|
}
|
|
|
|
- (void)addChild:(BookmarkBase *)child atIndex:(NSInteger)index
|
|
|
|
{
|
|
|
|
}
|
|
|
|
- (BOOL)hasDescendant:(BookmarkBase *)needle
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
|
|
|
- (BOOL)canContainChildren
|
|
|
|
{
|
|
|
|
return NO;
|
|
|
|
}
|
2013-02-14 17:59:12 +04:00
|
|
|
@end
|