mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 00:14:11 +09:00
iOS: initial release of iFreeRDP
This is the initial release of iFreeRDP the FreeRDP iOS client. Build instructions can be found in docs/README.ios.
This commit is contained in:
19
client/iOS/Controllers/AboutController.h
Normal file
19
client/iOS/Controllers/AboutController.h
Normal file
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
Application info controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
|
||||
@interface AboutController : UIViewController <UIWebViewDelegate, UIAlertViewDelegate>
|
||||
{
|
||||
NSString* last_link_clicked;
|
||||
UIWebView* webView;
|
||||
}
|
||||
|
||||
@end
|
||||
99
client/iOS/Controllers/AboutController.m
Normal file
99
client/iOS/Controllers/AboutController.m
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Application info controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "AboutController.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation AboutController
|
||||
|
||||
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
|
||||
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
|
||||
|
||||
// set title and tab-bar image
|
||||
[self setTitle:NSLocalizedString(@"About", @"About Controller title")];
|
||||
UIImage* tabBarIcon = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tabbar_icon_about" ofType:@"png"]];
|
||||
[self setTabBarItem:[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"About", @"Tabbar item about") image:tabBarIcon tag:0]];
|
||||
|
||||
last_link_clicked = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
[last_link_clicked release];
|
||||
}
|
||||
|
||||
// Implement loadView to create a view hierarchy programmatically, without using a nib.
|
||||
- (void)loadView
|
||||
{
|
||||
webView = [[[UIWebView alloc] initWithFrame:CGRectZero] autorelease];
|
||||
[webView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
|
||||
[webView setAutoresizesSubviews:YES];
|
||||
[webView setDelegate:self];
|
||||
[webView setDataDetectorTypes:UIDataDetectorTypeNone];
|
||||
[self setView:webView];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
NSString *filename = (IsPhone() ? @"about_phone" : @"about");
|
||||
NSString *htmlString = [[[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:filename ofType:@"html" inDirectory:@"about_page"] encoding:NSUTF8StringEncoding error:nil] autorelease];
|
||||
|
||||
[webView loadHTMLString:[NSString stringWithFormat:htmlString,
|
||||
TSXAppFullVersion(),
|
||||
[[UIDevice currentDevice] systemName],
|
||||
[[UIDevice currentDevice] systemVersion],
|
||||
[[UIDevice currentDevice] model]] baseURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"about_page"]]];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark UIWebView callbacks
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
|
||||
{
|
||||
if([[request URL] isFileURL])
|
||||
return YES;
|
||||
|
||||
if(navigationType == UIWebViewNavigationTypeLinkClicked)
|
||||
{
|
||||
[last_link_clicked release];
|
||||
last_link_clicked = [[[request URL] absoluteString] retain];
|
||||
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"External Link", @"External Link Alert Title")
|
||||
message:[NSString stringWithFormat:NSLocalizedString(@"Open [%@] in Browser?", @"Open link in browser (with link as parameter)"), last_link_clicked]
|
||||
delegate:self
|
||||
cancelButtonTitle:NSLocalizedString(@"OK", @"OK Button")
|
||||
otherButtonTitles:NSLocalizedString(@"No", @"No Button"), nil];
|
||||
[alert show];
|
||||
[alert release];
|
||||
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark UIAlertView delegate
|
||||
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
if (buttonIndex == 0)
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:last_link_clicked]];
|
||||
}
|
||||
|
||||
@end
|
||||
25
client/iOS/Controllers/AdvancedBookmarkEditorController.h
Normal file
25
client/iOS/Controllers/AdvancedBookmarkEditorController.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Controller to edit advanced bookmark settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ComputerBookmark;
|
||||
@class ConnectionParams;
|
||||
|
||||
@interface AdvancedBookmarkEditorController : EditorBaseController
|
||||
{
|
||||
@private
|
||||
ComputerBookmark* _bookmark;
|
||||
ConnectionParams* _params;
|
||||
}
|
||||
|
||||
// init for the given bookmark
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark;
|
||||
|
||||
@end
|
||||
310
client/iOS/Controllers/AdvancedBookmarkEditorController.m
Normal file
310
client/iOS/Controllers/AdvancedBookmarkEditorController.m
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
Controller to edit advanced bookmark settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "AdvancedBookmarkEditorController.h"
|
||||
#import "Bookmark.h"
|
||||
#import "Utils.h"
|
||||
#import "EditorSelectionController.h"
|
||||
#import "ScreenSelectionController.h"
|
||||
#import "PerformanceEditorController.h"
|
||||
|
||||
@interface AdvancedBookmarkEditorController ()
|
||||
|
||||
@end
|
||||
|
||||
#define SECTION_ADVANCED_SETTINGS 0
|
||||
#define SECTION_COUNT 1
|
||||
|
||||
@implementation AdvancedBookmarkEditorController
|
||||
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark
|
||||
{
|
||||
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
|
||||
{
|
||||
// set additional settings state according to bookmark data
|
||||
_bookmark = [bookmark retain];
|
||||
_params = [bookmark params];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self setTitle:NSLocalizedString(@"Advanced Settings", @"Advanced Settings title")];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// we need to reload the table view data here to have up-to-date data for the
|
||||
// advanced settings accessory items (like for resolution/color mode settings)
|
||||
[[self tableView] reloadData];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return SECTION_COUNT;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
// Return the number of rows in the section.
|
||||
switch (section)
|
||||
{
|
||||
case SECTION_ADVANCED_SETTINGS: // advanced settings
|
||||
return 7;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_ADVANCED_SETTINGS:
|
||||
return NSLocalizedString(@"Advanced", @"'Advanced': advanced settings header");
|
||||
}
|
||||
return @"unknown";
|
||||
}
|
||||
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// determine the required cell type
|
||||
NSString* cellType = nil;
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_ADVANCED_SETTINGS: // advanced settings
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0: // 3G Settings
|
||||
cellType = TableCellIdentifierYesNo;
|
||||
break;
|
||||
case 1: // 3G screen/color depth
|
||||
cellType = TableCellIdentifierSelection;
|
||||
break;
|
||||
case 2: // 3G performance settings
|
||||
cellType = TableCellIdentifierSubEditor;
|
||||
break;
|
||||
case 3: // security mode
|
||||
cellType = TableCellIdentifierSelection;
|
||||
break;
|
||||
case 4: // remote program
|
||||
case 5: // work dir
|
||||
cellType = TableCellIdentifierText;
|
||||
break;
|
||||
case 6: // console mode
|
||||
cellType = TableCellIdentifierYesNo;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
NSAssert(cellType != nil, @"Couldn't determine cell type");
|
||||
|
||||
// get the table view cell
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
// set cell values
|
||||
switch([indexPath section])
|
||||
{
|
||||
// advanced settings
|
||||
case SECTION_ADVANCED_SETTINGS:
|
||||
[self initAdvancedSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
// updates advanced settings in the UI
|
||||
- (void)initAdvancedSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
BOOL enable_3G_settings = [_params boolForKey:@"enable_3g_settings"];
|
||||
switch(indexPath.row)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"3G Settings", @"'3G Settings': Bookmark enable 3G settings")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[_params boolForKey:@"enable_3g_settings"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditSelectionTableViewCell* selCell = (EditSelectionTableViewCell*)cell;
|
||||
[[selCell label] setText:NSLocalizedString(@"3G Screen", @"'3G Screen': Bookmark 3G Screen settings")];
|
||||
NSString* resolution = ScreenResolutionDescription([_params intForKeyPath:@"settings_3g.screen_resolution_type"], [_params intForKeyPath:@"settings_3g.width"], [_params intForKeyPath:@"settings_3g.height"]);
|
||||
int colorBits = [_params intForKeyPath:@"settings_3g.colors"];
|
||||
[[selCell selection] setText:[NSString stringWithFormat:@"%@@%d", resolution, colorBits]];
|
||||
[[selCell label] setEnabled:enable_3G_settings];
|
||||
[[selCell selection] setEnabled:enable_3G_settings];
|
||||
[selCell setSelectionStyle:enable_3G_settings ? UITableViewCellSelectionStyleBlue : UITableViewCellSelectionStyleNone];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
EditSubEditTableViewCell* editCell = (EditSubEditTableViewCell*)cell;
|
||||
[[editCell label] setText:NSLocalizedString(@"3G Performance", @"'3G Performance': Bookmark 3G Performance Settings")];
|
||||
[[editCell label] setEnabled:enable_3G_settings];
|
||||
[editCell setSelectionStyle:enable_3G_settings ? UITableViewCellSelectionStyleBlue : UITableViewCellSelectionStyleNone];
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
EditSelectionTableViewCell* selCell = (EditSelectionTableViewCell*)cell;
|
||||
[[selCell label] setText:NSLocalizedString(@"Security", @"'Security': Bookmark protocl security settings")];
|
||||
[[selCell selection] setText:ProtocolSecurityDescription([_params intForKey:@"security"])];
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell label] setText:NSLocalizedString(@"Remote Program", @"'Remote Program': Bookmark remote program settings")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"remote_program"]];
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
[self adjustEditTextTableViewCell:textCell];
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell label] setText:NSLocalizedString(@"Working Directory", @"'Working Directory': Bookmark working directory settings")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"working_dir"]];
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
[self adjustEditTextTableViewCell:textCell];
|
||||
break;
|
||||
}
|
||||
case 6:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Console Mode", @"'Console Mode': Bookmark console mode settings")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[_params boolForKey:@"console"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UIViewController* viewCtrl = nil;
|
||||
|
||||
// determine view
|
||||
switch ([indexPath row])
|
||||
{
|
||||
case 1:
|
||||
if ([_params boolForKey:@"enable_3g_settings"])
|
||||
viewCtrl = [[[ScreenSelectionController alloc] initWithConnectionParams:_params keyPath:@"settings_3g"] autorelease];
|
||||
break;
|
||||
case 2:
|
||||
if ([_params boolForKey:@"enable_3g_settings"])
|
||||
viewCtrl = [[[PerformanceEditorController alloc] initWithConnectionParams:_params keyPath:@"settings_3g"] autorelease];
|
||||
break;
|
||||
case 3:
|
||||
viewCtrl = [[[EditorSelectionController alloc] initWithConnectionParams:_params entries:[NSArray arrayWithObject:@"security"] selections:[NSArray arrayWithObject:SelectionForSecuritySetting()]] autorelease];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// display view
|
||||
if(viewCtrl)
|
||||
[[self navigationController] pushViewController:viewCtrl animated:YES];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Text Field delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
switch(textField.tag)
|
||||
{
|
||||
// update remote program/work dir settings
|
||||
case GET_TAG(SECTION_ADVANCED_SETTINGS, 4):
|
||||
{
|
||||
[_params setValue:[textField text] forKey:@"remote_program"];
|
||||
break;
|
||||
}
|
||||
|
||||
case GET_TAG(SECTION_ADVANCED_SETTINGS, 5):
|
||||
{
|
||||
[_params setValue:[textField text] forKey:@"working_dir"];
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Action handlers
|
||||
|
||||
- (void)toggleSettingValue:(id)sender
|
||||
{
|
||||
UISwitch* valueSwitch = (UISwitch*)sender;
|
||||
switch(valueSwitch.tag)
|
||||
{
|
||||
case GET_TAG(SECTION_ADVANCED_SETTINGS, 0):
|
||||
[_params setBool:[valueSwitch isOn] forKey:@"enable_3g_settings"];
|
||||
NSArray* indexPaths = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:1 inSection:SECTION_ADVANCED_SETTINGS], [NSIndexPath indexPathForRow:2 inSection:SECTION_ADVANCED_SETTINGS], nil];
|
||||
[[self tableView] reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_ADVANCED_SETTINGS, 6):
|
||||
[_params setBool:[valueSwitch isOn] forKey:@"console"];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
14
client/iOS/Controllers/AppSettingsController.h
Normal file
14
client/iOS/Controllers/AppSettingsController.h
Normal file
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
Controller to specify application wide settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@interface AppSettingsController : EditorBaseController
|
||||
|
||||
@end
|
||||
309
client/iOS/Controllers/AppSettingsController.m
Normal file
309
client/iOS/Controllers/AppSettingsController.m
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
Controller to specify application wide settings
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "AppSettingsController.h"
|
||||
#import "Utils.h"
|
||||
#import "Toast+UIView.h"
|
||||
|
||||
@implementation AppSettingsController
|
||||
|
||||
// keep this up-to-date for correct section display/hidding
|
||||
#define SECTION_UI_SETTINGS 0
|
||||
#define SECTION_CERTIFICATE_HANDLING_SETTINGS 1
|
||||
#define SECTION_NUM_SECTIONS 2
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
|
||||
- (id)initWithStyle:(UITableViewStyle)style
|
||||
{
|
||||
if ((self = [super initWithStyle:style]))
|
||||
{
|
||||
UIImage* tabBarIcon = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tabbar_icon_settings" ofType:@"png"]];
|
||||
[self setTabBarItem:[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"Settings", @"Tabbar item settings") image:tabBarIcon tag:0]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark View lifecycle
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// set title
|
||||
[self setTitle:NSLocalizedString(@"Settings", @"App Settings title")];
|
||||
}
|
||||
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated {
|
||||
[super viewWillDisappear:animated];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return SECTION_NUM_SECTIONS;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
// Return the number of rows in the section.
|
||||
switch (section)
|
||||
{
|
||||
case SECTION_UI_SETTINGS: // UI settings
|
||||
return 5;
|
||||
case SECTION_CERTIFICATE_HANDLING_SETTINGS: // certificate handling settings
|
||||
return 2;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_UI_SETTINGS:
|
||||
return NSLocalizedString(@"User Interface", @"UI settings section title");
|
||||
case SECTION_CERTIFICATE_HANDLING_SETTINGS:
|
||||
return NSLocalizedString(@"Server Certificate Handling", @"Server Certificate Handling section title");
|
||||
default:
|
||||
return nil;
|
||||
}
|
||||
return @"unknown";
|
||||
}
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// determine the required cell type
|
||||
NSString* cellIdentifier = nil;
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_UI_SETTINGS:
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
cellIdentifier = TableCellIdentifierYesNo;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SECTION_CERTIFICATE_HANDLING_SETTINGS:
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
cellIdentifier = TableCellIdentifierYesNo;
|
||||
break;
|
||||
case 1:
|
||||
cellIdentifier = TableCellIdentifierSubEditor;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
NSAssert(cellIdentifier != nil, @"Couldn't determine cell type");
|
||||
|
||||
// get the table view cell
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellIdentifier];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
// set cell values
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_UI_SETTINGS:
|
||||
[self initUISettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
case SECTION_CERTIFICATE_HANDLING_SETTINGS:
|
||||
[self initCertificateHandlingSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Initialization helpers
|
||||
|
||||
// updates UI settings in the UI
|
||||
- (void)initUISettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Hide Status Bar", "Show/Hide Phone Status Bar setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_status_bar"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Hide Tool Bar", "Show/Hide Tool Bar setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_tool_bar"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Swap Mouse Buttons", "Swap Mouse Button UI setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.swap_mouse_buttons"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Invert Scrolling", "Invert Scrolling UI setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.invert_scrolling"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Touch Pointer Auto Scroll", "Touch Pointer Auto Scroll UI setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"ui.auto_scroll_touchpointer"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// updates certificate handling settings in the UI
|
||||
- (void)initCertificateHandlingSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditFlagTableViewCell* flagCell = (EditFlagTableViewCell*)cell;
|
||||
[[flagCell label] setText:NSLocalizedString(@"Accept all Certificates", "Accept All Certificates setting")];
|
||||
[[flagCell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[flagCell toggle] setOn:[[NSUserDefaults standardUserDefaults] boolForKey:@"security.accept_certificates"]];
|
||||
[[flagCell toggle] addTarget:self action:@selector(toggleSettingValue:) forControlEvents:UIControlEventValueChanged];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditSubEditTableViewCell* subCell = (EditSubEditTableViewCell*)cell;
|
||||
[[subCell label] setText:NSLocalizedString(@"Erase Certificate Cache", @"Erase certificate cache button")];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// deselect any row to fake a button-pressed like effect
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:YES];
|
||||
|
||||
// ensure everything is stored in our settings before we proceed
|
||||
[[self view] endEditing:NO];
|
||||
|
||||
// clear certificate cache
|
||||
if([indexPath section] == SECTION_CERTIFICATE_HANDLING_SETTINGS && [indexPath row] == 1)
|
||||
{
|
||||
// delete certificates cache
|
||||
NSError* err;
|
||||
if ([[NSFileManager defaultManager] removeItemAtPath:[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"/.freerdp"] error:&err])
|
||||
[[self view] makeToast:NSLocalizedString(@"Certificate Cache cleared!", @"Clear Certificate cache success message") duration:ToastDurationNormal position:@"center"];
|
||||
else
|
||||
[[self view] makeToast:NSLocalizedString(@"Error clearing the Certificate Cache!", @"Clear Certificate cache failed message") duration:ToastDurationNormal position:@"center"];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action Handlers
|
||||
|
||||
- (void)toggleSettingValue:(id)sender
|
||||
{
|
||||
UISwitch* valueSwitch = (UISwitch*)sender;
|
||||
switch([valueSwitch tag])
|
||||
{
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 0):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.hide_status_bar"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 1):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.hide_tool_bar"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 2):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.swap_mouse_buttons"];
|
||||
SetSwapMouseButtonsFlag([valueSwitch isOn]);
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 3):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.invert_scrolling"];
|
||||
SetInvertScrollingFlag([valueSwitch isOn]);
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_UI_SETTINGS, 4):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"ui.auto_scroll_touchpointer"];
|
||||
SetInvertScrollingFlag([valueSwitch isOn]);
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_CERTIFICATE_HANDLING_SETTINGS, 0):
|
||||
[[NSUserDefaults standardUserDefaults] setBool:[valueSwitch isOn] forKey:@"security.accept_certificates"];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
40
client/iOS/Controllers/BookmarkEditorController.h
Normal file
40
client/iOS/Controllers/BookmarkEditorController.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
Bookmark editor controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ComputerBookmark;
|
||||
@class ConnectionParams;
|
||||
|
||||
|
||||
@protocol BookmarkEditorDelegate <NSObject>
|
||||
// bookmark editing finsihed
|
||||
- (void)commitBookmark:(ComputerBookmark*)bookmark;
|
||||
@end
|
||||
|
||||
|
||||
@interface BookmarkEditorController : EditorBaseController <UIAlertViewDelegate>
|
||||
{
|
||||
@private
|
||||
ComputerBookmark* _bookmark;
|
||||
ConnectionParams* _params;
|
||||
|
||||
BOOL _display_server_settings;
|
||||
|
||||
id<BookmarkEditorDelegate> delegate;
|
||||
}
|
||||
|
||||
@property (nonatomic, assign) id<BookmarkEditorDelegate> delegate;
|
||||
|
||||
// init for the given bookmark
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark;
|
||||
|
||||
@end
|
||||
400
client/iOS/Controllers/BookmarkEditorController.m
Normal file
400
client/iOS/Controllers/BookmarkEditorController.m
Normal file
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
Bookmark editor controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "BookmarkEditorController.h"
|
||||
#import "Bookmark.h"
|
||||
#import "Utils.h"
|
||||
#import "ScreenSelectionController.h"
|
||||
#import "PerformanceEditorController.h"
|
||||
#import "CredentialsEditorController.h"
|
||||
#import "AdvancedBookmarkEditorController.h"
|
||||
|
||||
@implementation BookmarkEditorController
|
||||
|
||||
@synthesize delegate;
|
||||
|
||||
#define SECTION_SERVER 0
|
||||
#define SECTION_CREDENTIALS 1
|
||||
#define SECTION_SETTINGS 2
|
||||
#define SECTION_COUNT 3
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Initialization
|
||||
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark
|
||||
{
|
||||
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
|
||||
{
|
||||
// set additional settings state according to bookmark data
|
||||
_bookmark = [bookmark retain];
|
||||
_params = [bookmark params];
|
||||
|
||||
// if this is a TSX Connect bookmark - disable server settings
|
||||
if([_bookmark isKindOfClass:NSClassFromString(@"TSXConnectComputerBookmark")])
|
||||
_display_server_settings = NO;
|
||||
else
|
||||
_display_server_settings = YES;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark View lifecycle
|
||||
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// replace back button with a custom handler that checks if the required bookmark settings were specified
|
||||
UIBarButtonItem* saveButton = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Save", @"Save Button title") style:UIBarButtonItemStyleDone target:self action:@selector(handleSave:)] autorelease];
|
||||
UIBarButtonItem* cancelButton = [[[UIBarButtonItem alloc] initWithTitle:NSLocalizedString(@"Cancel", @"Cancel Button title") style:UIBarButtonItemStyleBordered target:self action:@selector(handleCancel:)] autorelease];
|
||||
[[self navigationItem] setLeftBarButtonItem:cancelButton];
|
||||
[[self navigationItem] setRightBarButtonItem:saveButton];
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated {
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// we need to reload the table view data here to have up-to-date data for the
|
||||
// advanced settings accessory items (like for resolution/color mode settings)
|
||||
[[self tableView] reloadData];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return SECTION_COUNT;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
// Return the number of rows in the section.
|
||||
switch (section)
|
||||
{
|
||||
case SECTION_SERVER: // server settings
|
||||
return (_display_server_settings ? 3 : 0);
|
||||
case SECTION_CREDENTIALS: // credentials
|
||||
return 1;
|
||||
case SECTION_SETTINGS: // session settings
|
||||
return 3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_SERVER:
|
||||
return (_display_server_settings ? NSLocalizedString(@"Host", @"'Host': host settings header") : nil);
|
||||
case SECTION_CREDENTIALS:
|
||||
return NSLocalizedString(@"Credentials", @"'Credentials': credentials settings header");
|
||||
case SECTION_SETTINGS:
|
||||
return NSLocalizedString(@"Settings", @"'Session Settings': session settings header");
|
||||
}
|
||||
return @"unknown";
|
||||
}
|
||||
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// determine the required cell type
|
||||
NSString* cellType = nil;
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_SERVER:
|
||||
cellType = TableCellIdentifierText;
|
||||
break;
|
||||
|
||||
case SECTION_CREDENTIALS:
|
||||
cellType = TableCellIdentifierSelection;
|
||||
break;
|
||||
|
||||
case SECTION_SETTINGS: // settings
|
||||
{
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0: // screen/color depth
|
||||
cellType = TableCellIdentifierSelection;
|
||||
break;
|
||||
case 1: // performance settings
|
||||
case 2: // advanced settings
|
||||
cellType = TableCellIdentifierSubEditor;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
NSAssert(cellType != nil, @"Couldn't determine cell type");
|
||||
|
||||
// get the table view cell
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
// set cell values
|
||||
switch([indexPath section])
|
||||
{
|
||||
// server settings
|
||||
case SECTION_SERVER:
|
||||
[self initServerSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
// credentials
|
||||
case SECTION_CREDENTIALS:
|
||||
[self initCredentialSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
// session settings
|
||||
case SECTION_SETTINGS:
|
||||
[self initSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
// updates server settings in the UI
|
||||
- (void)initServerSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
switch([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
[[textCell label] setText:NSLocalizedString(@"Label", @"'Label': Bookmark label")];
|
||||
[[textCell textfield] setText:[_bookmark label]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
case 1:
|
||||
[[textCell label] setText:NSLocalizedString(@"Host", @"'Host': Bookmark hostname")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"hostname"]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
case 2:
|
||||
[[textCell label] setText:NSLocalizedString(@"Port", @"'Port': Bookmark port")];
|
||||
[[textCell textfield] setText:[NSString stringWithFormat:@"%d", [_params intForKey:@"port"]]];
|
||||
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
|
||||
[self adjustEditTextTableViewCell:textCell];
|
||||
}
|
||||
|
||||
// updates credentials in the UI
|
||||
- (void)initCredentialSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
EditSelectionTableViewCell* selCell = (EditSelectionTableViewCell*)cell;
|
||||
switch(indexPath.row)
|
||||
{
|
||||
case 0:
|
||||
[[selCell label] setText:NSLocalizedString(@"Credentials", @"'Credentials': Bookmark credentials")];
|
||||
[[selCell selection] setText:[_params StringForKey:@"username"]];
|
||||
break;
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// updates session settings in the UI
|
||||
- (void)initSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
switch(indexPath.row)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditSelectionTableViewCell* selCell = (EditSelectionTableViewCell*)cell;
|
||||
[[selCell label] setText:NSLocalizedString(@"Screen", @"'Screen': Bookmark Screen settings")];
|
||||
NSString* resolution = ScreenResolutionDescription([_params intForKey:@"screen_resolution_type"], [_params intForKey:@"width"], [_params intForKey:@"height"]);
|
||||
int colorBits = [_params intForKey:@"colors"];
|
||||
[[selCell selection] setText:[NSString stringWithFormat:@"%@@%d", resolution, colorBits]];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditSubEditTableViewCell* editCell = (EditSubEditTableViewCell*)cell;
|
||||
[[editCell label] setText:NSLocalizedString(@"Performance", @"'Performance': Bookmark Performance Settings")];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
EditSubEditTableViewCell* editCell = (EditSubEditTableViewCell*)cell;
|
||||
[[editCell label] setText:NSLocalizedString(@"Advanced", @"'Advanced': Bookmark Advanced Settings")];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
UIViewController* viewCtrl = nil;
|
||||
|
||||
// determine view
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_CREDENTIALS:
|
||||
{
|
||||
if ([indexPath row] == 0)
|
||||
viewCtrl = [[[CredentialsEditorController alloc] initWithBookmark:_bookmark] autorelease];
|
||||
break;
|
||||
}
|
||||
|
||||
case SECTION_SETTINGS:
|
||||
{
|
||||
switch ([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
viewCtrl = [[[ScreenSelectionController alloc] initWithConnectionParams:_params] autorelease];
|
||||
break;
|
||||
case 1:
|
||||
viewCtrl = [[[PerformanceEditorController alloc] initWithConnectionParams:_params] autorelease];
|
||||
break;
|
||||
case 2:
|
||||
viewCtrl = [[[AdvancedBookmarkEditorController alloc] initWithBookmark:_bookmark] autorelease];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// display view
|
||||
if(viewCtrl)
|
||||
[[self navigationController] pushViewController:viewCtrl animated:YES];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Text Field delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
switch(textField.tag)
|
||||
{
|
||||
// update server settings
|
||||
case GET_TAG(SECTION_SERVER, 0):
|
||||
[_bookmark setLabel:[textField text]];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_SERVER, 1):
|
||||
[_params setValue:[textField text] forKey:@"hostname"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_SERVER, 2):
|
||||
[_params setInt:[[textField text] intValue] forKey:@"port"];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - UIAlertViewDelegate methods
|
||||
|
||||
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
// clicked yes?
|
||||
if (buttonIndex == 0)
|
||||
{
|
||||
// cancel bookmark editing and return to previous view controller
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action Handlers
|
||||
|
||||
- (void)handleSave:(id)sender
|
||||
{
|
||||
// resign any first responder (so that we finish editing any bookmark parameter that might be currently edited)
|
||||
[[self view] endEditing:NO];
|
||||
|
||||
// verify that bookmark is complete (only for manual bookmarks)
|
||||
if (![_bookmark isKindOfClass:NSClassFromString(@"TSXConnectComputerBookmark")])
|
||||
{
|
||||
if ([[_bookmark label] length] == 0 || [[_params StringForKey:@"hostname"] length] == 0 || [_params intForKey:@"port"] == 0)
|
||||
{
|
||||
UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Cancel without saving?", @"Incomplete bookmark error title") message:NSLocalizedString(@"Press 'Cancel' to abort!\nPress 'Continue' to specify the required fields!", @"Incomplete bookmark error message") delegate:self cancelButtonTitle:NSLocalizedString(@"Cancel", @"Cancel Button") otherButtonTitles:NSLocalizedString(@"Continue", @"Continue Button"), nil] autorelease];
|
||||
[alertView show];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// commit bookmark
|
||||
if ([[self delegate] respondsToSelector:@selector(commitBookmark:)])
|
||||
[[self delegate] commitBookmark:_bookmark];
|
||||
|
||||
// return to previous view controller
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)handleCancel:(id)sender
|
||||
{
|
||||
// return to previous view controller
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Memory management
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Relinquish ownership any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[super dealloc];
|
||||
[_bookmark autorelease];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
59
client/iOS/Controllers/BookmarkListController.h
Normal file
59
client/iOS/Controllers/BookmarkListController.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
bookmarks and active session view controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "Bookmark.h"
|
||||
#import "BookmarkTableCell.h"
|
||||
#import "SessionTableCell.h"
|
||||
#import "BookmarkEditorController.h"
|
||||
#import "Reachability.h"
|
||||
|
||||
@interface BookmarkListController : UIViewController <UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource, UIAlertViewDelegate, BookmarkEditorDelegate>
|
||||
{
|
||||
// custom bookmark and session table cells
|
||||
BookmarkTableCell* _bmTableCell;
|
||||
SessionTableCell* _sessTableCell;
|
||||
|
||||
// child views
|
||||
UISearchBar* _searchBar;
|
||||
UITableView* _tableView;
|
||||
|
||||
// array with search results (or nil if no search active)
|
||||
NSMutableArray* _manual_search_result;
|
||||
NSMutableArray* _tsxconnect_search_result;
|
||||
NSMutableArray* _history_search_result;
|
||||
|
||||
// bookmark arrays
|
||||
NSMutableArray* _manual_bookmarks;
|
||||
NSMutableArray* _tsxconnect_bookmarks;
|
||||
|
||||
// bookmark star images
|
||||
UIImage* _star_on_img;
|
||||
UIImage* _star_off_img;
|
||||
|
||||
// array with active sessions
|
||||
NSMutableArray* _active_sessions;
|
||||
|
||||
// array with connection history entries
|
||||
NSMutableArray* _connection_history;
|
||||
|
||||
// temporary bookmark when asking if the user wants to store a bookmark for a session initiated by a quick connect
|
||||
ComputerBookmark* _temporary_bookmark;
|
||||
|
||||
// reachability notification helper for tsx connect
|
||||
Reachability* _tsxconnect_reachability;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) IBOutlet UISearchBar* searchBar;
|
||||
@property (nonatomic, retain) IBOutlet UITableView* tableView;
|
||||
@property (nonatomic, retain) IBOutlet BookmarkTableCell* bmTableCell;
|
||||
@property (nonatomic, retain) IBOutlet SessionTableCell* sessTableCell;
|
||||
|
||||
|
||||
@end
|
||||
839
client/iOS/Controllers/BookmarkListController.m
Normal file
839
client/iOS/Controllers/BookmarkListController.m
Normal file
@@ -0,0 +1,839 @@
|
||||
/*
|
||||
bookmarks and active session view controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "BookmarkListController.h"
|
||||
#import "Utils.h"
|
||||
#import "BookmarkEditorController.h"
|
||||
#import "RDPSessionViewController.h"
|
||||
#import "Toast+UIView.h"
|
||||
#import "Reachability.h"
|
||||
|
||||
#define SECTION_SESSIONS 0
|
||||
#define SECTION_BOOKMARKS 1
|
||||
#define NUM_SECTIONS 2
|
||||
|
||||
@interface BookmarkListController (Private)
|
||||
#pragma mark misc functions
|
||||
- (UIButton*)disclosureButtonWithImage:(UIImage*)image;
|
||||
- (void)performSearch:(NSString*)searchText;
|
||||
#pragma mark Persisting bookmarks
|
||||
- (void)scheduleWriteBookmarksToDataStore;
|
||||
- (void)writeBookmarksToDataStore;
|
||||
- (void)scheduleWriteManualBookmarksToDataStore;
|
||||
- (void)writeManualBookmarksToDataStore;
|
||||
- (void)readManualBookmarksFromDataStore;
|
||||
- (void)writeArray:(NSArray*)bookmarks toDataStoreURL:(NSURL*)url;
|
||||
- (NSMutableArray*)arrayFromDataStoreURL:(NSURL*)url;
|
||||
- (NSURL*)manualBookmarksDataStoreURL;
|
||||
- (NSURL*)connectionHistoryDataStoreURL;
|
||||
@end
|
||||
|
||||
|
||||
@implementation BookmarkListController
|
||||
|
||||
@synthesize searchBar = _searchBar, tableView = _tableView, bmTableCell = _bmTableCell, sessTableCell = _sessTableCell;
|
||||
|
||||
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
|
||||
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
|
||||
{
|
||||
// load bookmarks
|
||||
[self readManualBookmarksFromDataStore];
|
||||
|
||||
// load connection history
|
||||
[self readConnectionHistoryFromDataStore];
|
||||
|
||||
// init search result array
|
||||
_manual_search_result = nil;
|
||||
|
||||
// register for session notifications
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionDisconnected:) name:TSXSessionDidDisconnectNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionFailedToConnect:) name:TSXSessionDidFailToConnectNotification object:nil];
|
||||
|
||||
// set title and tabbar controller image
|
||||
[self setTitle:NSLocalizedString(@"Connections", @"'Connections': bookmark controller title")];
|
||||
[self setTabBarItem:[[UITabBarItem alloc] initWithTabBarSystemItem:UITabBarSystemItemBookmarks tag:0]];
|
||||
|
||||
// load images
|
||||
_star_on_img = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"icon_accessory_star_on" ofType:@"png"]] retain];
|
||||
_star_off_img = [[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"icon_accessory_star_off" ofType:@"png"]] retain];
|
||||
|
||||
// init reachability detection
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) name:kReachabilityChangedNotification object:nil];
|
||||
|
||||
// init other properties
|
||||
_active_sessions = [[NSMutableArray alloc] init];
|
||||
_temporary_bookmark = nil;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
}
|
||||
|
||||
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
// set edit button to allow bookmark list editing
|
||||
[[self navigationItem] setRightBarButtonItem:[self editButtonItem]];
|
||||
|
||||
/*
|
||||
if (![[InAppPurchaseManager sharedInAppPurchaseManager] isProVersion])
|
||||
[[self navigationItem] setLeftBarButtonItem:[[UIBarButtonItem alloc] initWithTitle:@"Go Pro" style:UIBarButtonItemStyleDone target:self action:@selector(goProButtonPressed:)]];
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// in case we had a search - search again cause the bookmark searchable items could have changed
|
||||
if ([[_searchBar text] length] > 0)
|
||||
[self performSearch:[_searchBar text]];
|
||||
|
||||
// to reflect any bookmark changes - reload table
|
||||
[_tableView reloadData];
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// clear any search
|
||||
[_searchBar setText:@""];
|
||||
[_searchBar resignFirstResponder];
|
||||
[self performSearch:@""];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
// Return YES for supported orientations
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Release any cached data, images, etc that aren't in use.
|
||||
}
|
||||
|
||||
- (void)viewDidUnload {
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
// e.g. self.myOutlet = nil;
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[_tsxconnect_reachability stopNotifier];
|
||||
[_tsxconnect_reachability release];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
[_temporary_bookmark release];
|
||||
[_connection_history release];
|
||||
[_active_sessions release];
|
||||
[_tsxconnect_search_result release];
|
||||
[_manual_search_result release];
|
||||
[_manual_bookmarks release];
|
||||
[_tsxconnect_bookmarks release];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return NUM_SECTIONS;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_SESSIONS:
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case SECTION_BOOKMARKS:
|
||||
{
|
||||
// (+1 for Add Bookmark entry)
|
||||
if(_manual_search_result != nil)
|
||||
return ([_manual_search_result count] + [_history_search_result count] + 1);
|
||||
return ([_manual_bookmarks count] + 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (UITableViewCell*)cellForGenericListEntry
|
||||
{
|
||||
static NSString *CellIdentifier = @"BookmarkListCell";
|
||||
UITableViewCell *cell = [[self tableView] dequeueReusableCellWithIdentifier:CellIdentifier];
|
||||
if(cell == nil)
|
||||
{
|
||||
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
|
||||
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
[cell setAccessoryView:[self disclosureButtonWithImage:_star_off_img]];
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (BookmarkTableCell*)cellForBookmark
|
||||
{
|
||||
static NSString *BookmarkCellIdentifier = @"BookmarkCell";
|
||||
BookmarkTableCell *cell = (BookmarkTableCell*)[[self tableView] dequeueReusableCellWithIdentifier:BookmarkCellIdentifier];
|
||||
if(cell == nil)
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"BookmarkTableViewCell" owner:self options:nil];
|
||||
[_bmTableCell setAccessoryView:[self disclosureButtonWithImage:_star_on_img]];
|
||||
cell = _bmTableCell;
|
||||
_bmTableCell = nil;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
|
||||
switch ([indexPath section])
|
||||
{
|
||||
case SECTION_SESSIONS:
|
||||
{
|
||||
// get custom session cell
|
||||
static NSString *SessionCellIdentifier = @"SessionCell";
|
||||
SessionTableCell *cell = (SessionTableCell*)[tableView dequeueReusableCellWithIdentifier:SessionCellIdentifier];
|
||||
if(cell == nil)
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"SessionTableViewCell" owner:self options:nil];
|
||||
cell = _sessTableCell;
|
||||
_sessTableCell = nil;
|
||||
}
|
||||
|
||||
// set cell data
|
||||
RDPSession* session = [_active_sessions objectAtIndex:[indexPath row]];
|
||||
[[cell title] setText:[session sessionName]];
|
||||
[[cell server] setText:[[session params] StringForKey:@"hostname"]];
|
||||
if([[[cell server] text] length] == 0)
|
||||
[[cell server] setText:@"TSX Connect"];
|
||||
[[cell username] setText:[[session params] StringForKey:@"username"]];
|
||||
[[cell screenshot] setImage:[session getScreenshotWithSize:[[cell screenshot] bounds].size]];
|
||||
[[cell disconnectButton] setTag:[indexPath row]];
|
||||
return cell;
|
||||
}
|
||||
|
||||
case SECTION_BOOKMARKS:
|
||||
{
|
||||
// special handling for first cell - quick connect/quick create Bookmark cell
|
||||
if([indexPath row] == 0)
|
||||
{
|
||||
// if a search text is entered the cell becomes a quick connect/quick create bookmark cell - otherwise it's just an add bookmark cell
|
||||
UITableViewCell* cell = [self cellForGenericListEntry];
|
||||
if ([[_searchBar text] length] == 0)
|
||||
{
|
||||
[[cell textLabel] setText:[@" " stringByAppendingString:NSLocalizedString(@"Add Connection", @"'Add Connection': button label")]];
|
||||
[((UIButton*)[cell accessoryView]) setHidden:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
[[cell textLabel] setText:[@" " stringByAppendingString:[_searchBar text]]];
|
||||
[((UIButton*)[cell accessoryView]) setHidden:NO];
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
else
|
||||
{
|
||||
// do we have a history cell or bookmark cell?
|
||||
if ([self isIndexPathToHistoryItem:indexPath])
|
||||
{
|
||||
UITableViewCell* cell = [self cellForGenericListEntry];
|
||||
[[cell textLabel] setText:[@" " stringByAppendingString:[_history_search_result objectAtIndex:[self historyIndexFromIndexPath:indexPath]]]];
|
||||
[((UIButton*)[cell accessoryView]) setHidden:NO];
|
||||
return cell;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set cell properties
|
||||
ComputerBookmark* entry;
|
||||
BookmarkTableCell* cell = [self cellForBookmark];
|
||||
if(_manual_search_result == nil)
|
||||
entry = [_manual_bookmarks objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]];
|
||||
else
|
||||
entry = [[_manual_search_result objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]] valueForKey:@"bookmark"];
|
||||
|
||||
[[cell title] setText:[entry label]];
|
||||
[[cell subTitle] setText:[[entry params] StringForKey:@"hostname"]];
|
||||
return cell;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
NSAssert(0, @"Failed to create cell");
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Override to support conditional editing of the table view.
|
||||
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// dont allow to edit Add Bookmark item
|
||||
if([indexPath section] == SECTION_SESSIONS)
|
||||
return NO;
|
||||
if([indexPath section] == SECTION_BOOKMARKS && [indexPath row] == 0)
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Override to support editing the table view.
|
||||
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if(editingStyle == UITableViewCellEditingStyleDelete)
|
||||
{
|
||||
// Delete the row from the data source
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_BOOKMARKS:
|
||||
{
|
||||
if (_manual_search_result == nil)
|
||||
[_manual_bookmarks removeObjectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]];
|
||||
else
|
||||
{
|
||||
// history item or bookmark?
|
||||
if ([self isIndexPathToHistoryItem:indexPath])
|
||||
{
|
||||
[_connection_history removeObject:[_history_search_result objectAtIndex:[self historyIndexFromIndexPath:indexPath]]];
|
||||
[_history_search_result removeObjectAtIndex:[self historyIndexFromIndexPath:indexPath]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_manual_bookmarks removeObject:[[_manual_search_result objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]] valueForKey:@"bookmark"]];
|
||||
[_manual_search_result removeObjectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]];
|
||||
}
|
||||
}
|
||||
[self scheduleWriteManualBookmarksToDataStore];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[tableView reloadSections:[NSIndexSet indexSetWithIndex:[indexPath section]] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Override to support rearranging the table view.
|
||||
- (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath
|
||||
{
|
||||
if([fromIndexPath compare:toIndexPath] != NSOrderedSame)
|
||||
{
|
||||
switch([fromIndexPath section])
|
||||
{
|
||||
case SECTION_BOOKMARKS:
|
||||
{
|
||||
int fromIdx = [self bookmarkIndexFromIndexPath:fromIndexPath];
|
||||
int toIdx = [self bookmarkIndexFromIndexPath:toIndexPath];
|
||||
ComputerBookmark* temp_bookmark = [[_manual_bookmarks objectAtIndex:fromIdx] retain];
|
||||
[_manual_bookmarks removeObjectAtIndex:fromIdx];
|
||||
if (toIdx >= [_manual_bookmarks count])
|
||||
[_manual_bookmarks addObject:temp_bookmark];
|
||||
else
|
||||
[_manual_bookmarks insertObject:temp_bookmark atIndex:toIdx];
|
||||
[temp_bookmark release];
|
||||
|
||||
[self scheduleWriteManualBookmarksToDataStore];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// prevent that an item is moved befoer the Add Bookmark item
|
||||
-(NSIndexPath*)tableView:(UITableView *)tableView targetIndexPathForMoveFromRowAtIndexPath:(NSIndexPath *)sourceIndexPath toProposedIndexPath:(NSIndexPath *)proposedDestinationIndexPath
|
||||
{
|
||||
// don't allow to move:
|
||||
// - items between sections
|
||||
// - the quick connect/quick create bookmark cell
|
||||
// - any item while a search is applied
|
||||
if([proposedDestinationIndexPath row] == 0 || ([sourceIndexPath section] != [proposedDestinationIndexPath section]) ||
|
||||
_manual_search_result != nil || _tsxconnect_search_result != nil)
|
||||
{
|
||||
return sourceIndexPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return proposedDestinationIndexPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Override to support conditional rearranging of the table view.
|
||||
- (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
// dont allow to reorder Add Bookmark item
|
||||
if([indexPath section] == SECTION_BOOKMARKS && [indexPath row] == 0)
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (NSString*)tableView:(UITableView*)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if(section == SECTION_SESSIONS && [_active_sessions count] > 0)
|
||||
return NSLocalizedString(@"My Sessions", @"'My Session': section sessions header");
|
||||
if(section == SECTION_BOOKMARKS)
|
||||
return NSLocalizedString(@"Manual Connections", @"'Manual Connections': section manual bookmarks header");
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString*)tableView:(UITableView*)tableView titleForFooterInSection:(NSInteger)section
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if([indexPath section] == SECTION_SESSIONS)
|
||||
return 72;
|
||||
return [tableView rowHeight];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view delegate
|
||||
|
||||
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
|
||||
{
|
||||
[super setEditing:editing animated:animated];
|
||||
[[self tableView] setEditing:editing animated:animated];
|
||||
}
|
||||
|
||||
- (void)accessoryButtonTapped:(UIControl*)button withEvent:(UIEvent*)event
|
||||
{
|
||||
// forward a tap on our custom accessory button to the real accessory button handler
|
||||
NSIndexPath* indexPath = [[self tableView] indexPathForRowAtPoint:[[[event touchesForView:button] anyObject] locationInView:[self tableView]]];
|
||||
if (indexPath == nil)
|
||||
return;
|
||||
|
||||
[[[self tableView] delegate] tableView:[self tableView] accessoryButtonTappedForRowWithIndexPath:indexPath];
|
||||
}
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
if([indexPath section] == SECTION_SESSIONS)
|
||||
{
|
||||
// resume session
|
||||
RDPSession* session = [_active_sessions objectAtIndex:[indexPath row]];
|
||||
UIViewController* ctrl = [[RDPSessionViewController alloc] initWithNibName:@"RDPSessionView" bundle:nil session:session];
|
||||
[ctrl setHidesBottomBarWhenPushed:YES];
|
||||
[[self navigationController] pushViewController:ctrl animated:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
ComputerBookmark* bookmark = nil;
|
||||
if([indexPath section] == SECTION_BOOKMARKS)
|
||||
{
|
||||
// first row has either quick connect or add bookmark item
|
||||
if([indexPath row] == 0)
|
||||
{
|
||||
if ([[_searchBar text] length] == 0)
|
||||
{
|
||||
// show add bookmark controller
|
||||
BookmarkEditorController* bookmarkEditorController = [[[BookmarkEditorController alloc] initWithBookmark:[[ComputerBookmark alloc] initWithBaseDefaultParameters]] autorelease];
|
||||
[bookmarkEditorController setTitle:NSLocalizedString(@"Add Connection", @"Add Connection title")];
|
||||
[bookmarkEditorController setDelegate:self];
|
||||
[bookmarkEditorController setHidesBottomBarWhenPushed:YES];
|
||||
[[self navigationController] pushViewController:bookmarkEditorController animated:YES];
|
||||
}
|
||||
else
|
||||
{
|
||||
// create a quick connect bookmark and add an entry to the quick connect history (if not already in the history)
|
||||
bookmark = [self bookmarkForQuickConnectTo:[_searchBar text]];
|
||||
if (![_connection_history containsObject:[_searchBar text]])
|
||||
{
|
||||
[_connection_history addObject:[_searchBar text]];
|
||||
[self scheduleWriteConnectionHistoryToDataStore];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(_manual_search_result != nil)
|
||||
{
|
||||
if ([self isIndexPathToHistoryItem:indexPath])
|
||||
{
|
||||
// create a quick connect bookmark for a history item
|
||||
NSString* item = [_history_search_result objectAtIndex:[self historyIndexFromIndexPath:indexPath]];
|
||||
bookmark = [self bookmarkForQuickConnectTo:item];
|
||||
}
|
||||
else
|
||||
bookmark = [[_manual_search_result objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]] valueForKey:@"bookmark"];
|
||||
}
|
||||
else
|
||||
bookmark = [_manual_bookmarks objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]]; // -1 because of ADD BOOKMARK entry
|
||||
}
|
||||
|
||||
// set reachability status
|
||||
WakeUpWWAN();
|
||||
[bookmark setConntectedViaWLAN:[[Reachability reachabilityWithHostName:[[bookmark params] StringForKey:@"hostname"]] currentReachabilityStatus] == ReachableViaWiFi];
|
||||
}
|
||||
|
||||
if(bookmark != nil)
|
||||
{
|
||||
// create rdp session
|
||||
RDPSession* session = [[[RDPSession alloc] initWithBookmark:bookmark] autorelease];
|
||||
UIViewController* ctrl = [[RDPSessionViewController alloc] initWithNibName:@"RDPSessionView" bundle:nil session:session];
|
||||
[ctrl setHidesBottomBarWhenPushed:YES];
|
||||
[[self navigationController] pushViewController:ctrl animated:YES];
|
||||
[_active_sessions addObject:session];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)tableView:(UITableView*)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath*)indexPath
|
||||
{
|
||||
// get the bookmark
|
||||
NSString* bookmark_editor_title = NSLocalizedString(@"Edit Connection", @"Edit Connection title");
|
||||
ComputerBookmark* bookmark = nil;
|
||||
if ([indexPath section] == SECTION_BOOKMARKS)
|
||||
{
|
||||
if ([indexPath row] == 0)
|
||||
{
|
||||
// create a new bookmark and init hostname and label
|
||||
bookmark = [self bookmarkForQuickConnectTo:[_searchBar text]];
|
||||
bookmark_editor_title = NSLocalizedString(@"Add Connection", @"Add Connection title");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_manual_search_result != nil)
|
||||
{
|
||||
if ([self isIndexPathToHistoryItem:indexPath])
|
||||
{
|
||||
// create a new bookmark and init hostname and label
|
||||
NSString* item = [_history_search_result objectAtIndex:[self historyIndexFromIndexPath:indexPath]];
|
||||
bookmark = [self bookmarkForQuickConnectTo:item];
|
||||
bookmark_editor_title = NSLocalizedString(@"Add Connection", @"Add Connection title");
|
||||
}
|
||||
else
|
||||
bookmark = [[_manual_search_result objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]] valueForKey:@"bookmark"];
|
||||
}
|
||||
else
|
||||
bookmark = [_manual_bookmarks objectAtIndex:[self bookmarkIndexFromIndexPath:indexPath]]; // -1 because of ADD BOOKMARK entry
|
||||
}
|
||||
}
|
||||
|
||||
// bookmark found? - start the editor
|
||||
if (bookmark != nil)
|
||||
{
|
||||
BookmarkEditorController* editBookmarkController = [[[BookmarkEditorController alloc] initWithBookmark:bookmark] autorelease];
|
||||
[editBookmarkController setHidesBottomBarWhenPushed:YES];
|
||||
[editBookmarkController setTitle:bookmark_editor_title];
|
||||
[editBookmarkController setDelegate:self];
|
||||
[[self navigationController] pushViewController:editBookmarkController animated:YES];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Search Bar Delegates
|
||||
|
||||
- (BOOL)searchBarShouldBeginEditing:(UISearchBar*)searchBar
|
||||
{
|
||||
// show cancel button
|
||||
[searchBar setShowsCancelButton:YES animated:YES];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
// clear search result
|
||||
[_tsxconnect_search_result release];
|
||||
_tsxconnect_search_result = nil;
|
||||
[_manual_search_result release];
|
||||
_manual_search_result = nil;
|
||||
|
||||
// clear text and remove cancel button
|
||||
[searchBar setText:@""];
|
||||
[searchBar resignFirstResponder];
|
||||
}
|
||||
|
||||
- (BOOL)searchBarShouldEndEditing:(UISearchBar*)searchBar
|
||||
{
|
||||
[searchBar setShowsCancelButton:NO animated:YES];
|
||||
|
||||
// re-enable table selection
|
||||
[_tableView setAllowsSelection:YES];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
[_searchBar resignFirstResponder];
|
||||
}
|
||||
|
||||
- (void)searchBar:(UISearchBar*)searchBar textDidChange:(NSString*)searchText
|
||||
{
|
||||
[self performSearch:searchText];
|
||||
[_tableView reloadData];
|
||||
}
|
||||
|
||||
#pragma mark - Session handling
|
||||
|
||||
// session was added
|
||||
- (void)sessionDisconnected:(NSNotification*)notification
|
||||
{
|
||||
// remove session from active sessions
|
||||
RDPSession* session = (RDPSession*)[notification object];
|
||||
[_active_sessions removeObject:session];
|
||||
|
||||
// if this view is currently active refresh tsxconnect entries
|
||||
if([[self navigationController] visibleViewController] == self)
|
||||
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:SECTION_SESSIONS] withRowAnimation:UITableViewRowAnimationNone];
|
||||
|
||||
// if session's bookmark is not in the bookmark list ask the user if he wants to add it
|
||||
// (this happens if the session is created using the quick connect feature)
|
||||
if (![[session bookmark] isKindOfClass:NSClassFromString(@"TSXConnectComputerBookmark")] &&
|
||||
![_manual_bookmarks containsObject:[session bookmark]])
|
||||
{
|
||||
// retain the bookmark in case we want to save it later
|
||||
_temporary_bookmark = [[session bookmark] retain];
|
||||
|
||||
// ask the user if he wants to save the bookmark
|
||||
NSString* title = NSLocalizedString(@"Save Connection Settings?", @"Save connection settings title");
|
||||
NSString* message = NSLocalizedString(@"Your Connection Settings have not been saved. Do you want to save them?", @"Save connection settings message");
|
||||
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:title message:message delegate:self
|
||||
cancelButtonTitle:NSLocalizedString(@"Yes", @"Yes Button") otherButtonTitles:NSLocalizedString(@"No", @"No Button"), nil];
|
||||
[alert show];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sessionFailedToConnect:(NSNotification*)notification
|
||||
{
|
||||
// remove session from active sessions
|
||||
RDPSession* session = (RDPSession*)[notification object];
|
||||
[_active_sessions removeObject:session];
|
||||
|
||||
// display error toast
|
||||
[[self view] makeToast:NSLocalizedString(@"Failed to connect to session!", @"Failed to connect error message") duration:ToastDurationNormal position:@"center"];
|
||||
}
|
||||
|
||||
#pragma mark - UIAlertView delegates
|
||||
|
||||
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
|
||||
{
|
||||
// yes clicked?
|
||||
if (buttonIndex == 0 && _temporary_bookmark)
|
||||
{
|
||||
[_manual_bookmarks addObject:_temporary_bookmark];
|
||||
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:SECTION_BOOKMARKS] withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
|
||||
[_temporary_bookmark autorelease];
|
||||
_temporary_bookmark = nil;
|
||||
}
|
||||
|
||||
#pragma mark - Reachability notification
|
||||
- (void)reachabilityChanged:(NSNotification*)notification
|
||||
{
|
||||
// no matter how the network changed - we will disconnect
|
||||
// disconnect session (if there is any)
|
||||
if ([_active_sessions count] > 0)
|
||||
{
|
||||
RDPSession* session = [_active_sessions objectAtIndex:0];
|
||||
[session disconnect];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - BookmarkEditorController delegate
|
||||
|
||||
- (void)commitBookmark:(ComputerBookmark *)bookmark
|
||||
{
|
||||
// if we got a manual bookmark that is not in the list yet - add it
|
||||
if (![_manual_bookmarks containsObject:bookmark])
|
||||
[_manual_bookmarks addObject:bookmark];
|
||||
|
||||
// remove any quick connect history entry with the same hostname
|
||||
NSString* hostname = [[bookmark params] StringForKey:@"hostname"];
|
||||
if ([_connection_history containsObject:hostname])
|
||||
{
|
||||
[_connection_history removeObject:hostname];
|
||||
[self scheduleWriteConnectionHistoryToDataStore];
|
||||
}
|
||||
|
||||
[self scheduleWriteManualBookmarksToDataStore];
|
||||
}
|
||||
|
||||
- (IBAction)disconnectButtonPressed:(id)sender
|
||||
{
|
||||
// disconnect session and refresh table view
|
||||
RDPSession* session = [_active_sessions objectAtIndex:[sender tag]];
|
||||
[session disconnect];
|
||||
}
|
||||
|
||||
#pragma mark - Misc functions
|
||||
|
||||
- (BOOL)hasNoBookmarks
|
||||
{
|
||||
return ([_manual_bookmarks count] == 0 && [_tsxconnect_bookmarks count] == 0);
|
||||
}
|
||||
|
||||
- (UIButton*)disclosureButtonWithImage:(UIImage*)image
|
||||
{
|
||||
// we make the button a little bit bigger (image widht * 2, height + 10) so that the user doesn't accidentally connect to the bookmark ...
|
||||
UIButton* button = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[button setFrame:CGRectMake(0, 0, [image size].width * 2, [image size].height + 10)];
|
||||
[button setImage:image forState:UIControlStateNormal];
|
||||
[button addTarget:self action:@selector(accessoryButtonTapped:withEvent:) forControlEvents:UIControlEventTouchUpInside];
|
||||
[button setUserInteractionEnabled:YES];
|
||||
return button;
|
||||
}
|
||||
|
||||
- (void)performSearch:(NSString*)searchText
|
||||
{
|
||||
[_manual_search_result autorelease];
|
||||
[_tsxconnect_search_result autorelease];
|
||||
|
||||
if([searchText length] > 0)
|
||||
{
|
||||
_manual_search_result = [FilterBookmarks(_manual_bookmarks, [searchText componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) retain];
|
||||
_tsxconnect_search_result = [FilterBookmarks(_tsxconnect_bookmarks, [searchText componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) retain];
|
||||
_history_search_result = [FilterHistory(_connection_history, searchText) retain];
|
||||
}
|
||||
else
|
||||
{
|
||||
_history_search_result = nil;
|
||||
_tsxconnect_search_result = nil;
|
||||
_manual_search_result = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (int)bookmarkIndexFromIndexPath:(NSIndexPath*)indexPath
|
||||
{
|
||||
return [indexPath row] - ((_history_search_result != nil) ? [_history_search_result count] : 0) - 1;
|
||||
}
|
||||
|
||||
- (int)historyIndexFromIndexPath:(NSIndexPath*)indexPath
|
||||
{
|
||||
return [indexPath row] - 1;
|
||||
}
|
||||
|
||||
- (BOOL)isIndexPathToHistoryItem:(NSIndexPath*)indexPath
|
||||
{
|
||||
return (([indexPath row] - 1) < [_history_search_result count]);
|
||||
}
|
||||
|
||||
- (ComputerBookmark*)bookmarkForQuickConnectTo:(NSString*)host
|
||||
{
|
||||
ComputerBookmark* bookmark = [[[ComputerBookmark alloc] initWithBaseDefaultParameters] autorelease];
|
||||
[bookmark setLabel:host];
|
||||
[[bookmark params] setValue:host forKey:@"hostname"];
|
||||
return bookmark;
|
||||
}
|
||||
|
||||
#pragma mark - Persisting bookmarks
|
||||
|
||||
- (void)scheduleWriteBookmarksToDataStore
|
||||
{
|
||||
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
||||
[self writeBookmarksToDataStore];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)writeBookmarksToDataStore
|
||||
{
|
||||
[self writeManualBookmarksToDataStore];
|
||||
}
|
||||
|
||||
- (void)scheduleWriteManualBookmarksToDataStore
|
||||
{
|
||||
[[NSOperationQueue mainQueue] addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(writeManualBookmarksToDataStore) object:nil] autorelease]];
|
||||
}
|
||||
|
||||
- (void)writeManualBookmarksToDataStore
|
||||
{
|
||||
[self writeArray:_manual_bookmarks toDataStoreURL:[self manualBookmarksDataStoreURL]];
|
||||
}
|
||||
|
||||
- (void)scheduleWriteConnectionHistoryToDataStore
|
||||
{
|
||||
[[NSOperationQueue mainQueue] addOperation:[[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(writeConnectionHistoryToDataStore) object:nil] autorelease]];
|
||||
}
|
||||
|
||||
- (void)writeConnectionHistoryToDataStore
|
||||
{
|
||||
[self writeArray:_connection_history toDataStoreURL:[self connectionHistoryDataStoreURL]];
|
||||
}
|
||||
|
||||
- (void)writeArray:(NSArray*)bookmarks toDataStoreURL:(NSURL*)url
|
||||
{
|
||||
NSData* archived_data = [NSKeyedArchiver archivedDataWithRootObject:bookmarks];
|
||||
[archived_data writeToURL:url atomically:YES];
|
||||
}
|
||||
|
||||
- (void)readManualBookmarksFromDataStore
|
||||
{
|
||||
[_manual_bookmarks autorelease];
|
||||
_manual_bookmarks = [self arrayFromDataStoreURL:[self manualBookmarksDataStoreURL]];
|
||||
|
||||
if(_manual_bookmarks == nil)
|
||||
_manual_bookmarks = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
||||
- (void)readConnectionHistoryFromDataStore
|
||||
{
|
||||
[_connection_history autorelease];
|
||||
_connection_history = [self arrayFromDataStoreURL:[self connectionHistoryDataStoreURL]];
|
||||
|
||||
if(_connection_history == nil)
|
||||
_connection_history = [[NSMutableArray alloc] init];
|
||||
}
|
||||
|
||||
- (NSMutableArray*)arrayFromDataStoreURL:(NSURL*)url
|
||||
{
|
||||
NSData* archived_data = [NSData dataWithContentsOfURL:url];
|
||||
|
||||
if (!archived_data)
|
||||
return nil;
|
||||
|
||||
return [[NSKeyedUnarchiver unarchiveObjectWithData:archived_data] retain];
|
||||
}
|
||||
|
||||
- (NSURL*)manualBookmarksDataStoreURL
|
||||
{
|
||||
return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], @"com.thinstuff.tsx-rdc-ios.bookmarks.plist"]];
|
||||
}
|
||||
|
||||
- (NSURL*)connectionHistoryDataStoreURL
|
||||
{
|
||||
return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], @"com.thinstuff.tsx-rdc-ios.connection_history.plist"]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
25
client/iOS/Controllers/CredentialsEditorController.h
Normal file
25
client/iOS/Controllers/CredentialsEditorController.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
Controller to edit bookmark credentials
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ComputerBookmark;
|
||||
@class ConnectionParams;
|
||||
|
||||
@interface CredentialsEditorController : EditorBaseController
|
||||
{
|
||||
@private
|
||||
ComputerBookmark* _bookmark;
|
||||
ConnectionParams* _params;
|
||||
}
|
||||
|
||||
// init for the given bookmark
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark;
|
||||
|
||||
@end
|
||||
203
client/iOS/Controllers/CredentialsEditorController.m
Normal file
203
client/iOS/Controllers/CredentialsEditorController.m
Normal file
@@ -0,0 +1,203 @@
|
||||
/*
|
||||
Controller to edit bookmark credentials
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "CredentialsEditorController.h"
|
||||
#import "Bookmark.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@interface CredentialsEditorController ()
|
||||
|
||||
@end
|
||||
|
||||
#define SECTION_CREDENTIALS 0
|
||||
#define SECTION_COUNT 1
|
||||
|
||||
@implementation CredentialsEditorController
|
||||
|
||||
- (id)initWithBookmark:(ComputerBookmark*)bookmark
|
||||
{
|
||||
if ((self = [super initWithStyle:UITableViewStyleGrouped]))
|
||||
{
|
||||
// set additional settings state according to bookmark data
|
||||
_bookmark = [bookmark retain];
|
||||
_params = [bookmark params];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
[self setTitle:NSLocalizedString(@"Credentials", @"Credentials title")];
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// foce any active editing to stop
|
||||
[[self view] endEditing:NO];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return SECTION_COUNT;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
// Return the number of rows in the section.
|
||||
switch (section)
|
||||
{
|
||||
case SECTION_CREDENTIALS: // credentials
|
||||
return 3;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case SECTION_CREDENTIALS:
|
||||
return NSLocalizedString(@"Credentials", @"'Credentials': credentials settings header");
|
||||
}
|
||||
return @"unknown";
|
||||
}
|
||||
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// determine the required cell type
|
||||
NSString* cellType = nil;
|
||||
switch([indexPath section])
|
||||
{
|
||||
case SECTION_CREDENTIALS: // credentials
|
||||
if([indexPath row] == 1)
|
||||
cellType = TableCellIdentifierSecretText; // password field
|
||||
else
|
||||
cellType = TableCellIdentifierText;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
NSAssert(cellType != nil, @"Couldn't determine cell type");
|
||||
|
||||
// get the table view cell
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:cellType];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
// set cell values
|
||||
switch([indexPath section])
|
||||
{
|
||||
// credentials
|
||||
case SECTION_CREDENTIALS:
|
||||
[self initCredentialSettings:indexPath cell:cell];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
|
||||
// updates credentials in the UI
|
||||
- (void)initCredentialSettings:(NSIndexPath*)indexPath cell:(UITableViewCell*)cell
|
||||
{
|
||||
switch(indexPath.row)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell label] setText:NSLocalizedString(@"Username", @"'Username': Bookmark username")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"username"]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
EditSecretTextTableViewCell* textCell = (EditSecretTextTableViewCell*)cell;
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell label] setText:NSLocalizedString(@"Password", @"'Password': Bookmark password")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"password"]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell textfield] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[textCell label] setText:NSLocalizedString(@"Domain", @"'Domain': Bookmark domain")];
|
||||
[[textCell textfield] setText:[_params StringForKey:@"domain"]];
|
||||
[[textCell textfield] setPlaceholder:NSLocalizedString(@"not set", @"not set placeholder")];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
NSLog(@"Invalid row index in settings table!");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Text Field delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
switch(textField.tag)
|
||||
{
|
||||
// update credentials settings
|
||||
case GET_TAG(SECTION_CREDENTIALS, 0):
|
||||
[_params setValue:[textField text] forKey:@"username"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_CREDENTIALS, 1):
|
||||
[_params setValue:[textField text] forKey:@"password"];
|
||||
break;
|
||||
|
||||
case GET_TAG(SECTION_CREDENTIALS, 2):
|
||||
[_params setValue:[textField text] forKey:@"domain"];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
31
client/iOS/Controllers/CredentialsInputController.h
Normal file
31
client/iOS/Controllers/CredentialsInputController.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
Credentials input controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RDPSession;
|
||||
|
||||
@interface CredentialsInputController : UIViewController
|
||||
{
|
||||
@private
|
||||
IBOutlet UITextField* _textfield_username;
|
||||
IBOutlet UITextField* _textfield_password;
|
||||
IBOutlet UITextField* _textfield_domain;
|
||||
IBOutlet UIButton* _btn_login;
|
||||
IBOutlet UIButton* _btn_cancel;
|
||||
IBOutlet UIScrollView* _scroll_view;
|
||||
IBOutlet UILabel* _lbl_message;
|
||||
|
||||
RDPSession* _session;
|
||||
NSMutableDictionary* _params;
|
||||
}
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession*)session params:(NSMutableDictionary*)params;
|
||||
|
||||
@end
|
||||
133
client/iOS/Controllers/CredentialsInputController.m
Normal file
133
client/iOS/Controllers/CredentialsInputController.m
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
Credentials input controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "CredentialsInputController.h"
|
||||
#import "RDPSession.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation CredentialsInputController
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession *)session params:(NSMutableDictionary *)params
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
_session = session;
|
||||
_params = params;
|
||||
[self setModalPresentationStyle:UIModalPresentationFormSheet];
|
||||
|
||||
// on iphone we have the problem that the buttons are hidden by the keyboard
|
||||
// we solve this issue by registering keyboard notification handlers and adjusting the scrollview accordingly
|
||||
if (IsPhone())
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name: UIKeyboardWillHideNotification object:nil];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
// set localized strings
|
||||
[_lbl_message setText:NSLocalizedString(@"Please provide the missing user information in order to proceed and login.", @"Credentials input view message")];
|
||||
[_textfield_username setPlaceholder:NSLocalizedString(@"Username", @"Credentials Input Username hint")];
|
||||
[_textfield_password setPlaceholder:NSLocalizedString(@"Password", @"Credentials Input Password hint")];
|
||||
[_textfield_domain setPlaceholder:NSLocalizedString(@"Domain", @"Credentials Input Domain hint")];
|
||||
[_btn_login setTitle:NSLocalizedString(@"Login", @"Login Button") forState:UIControlStateNormal];
|
||||
[_btn_cancel setTitle:NSLocalizedString(@"Cancel", @"Cancel Button") forState:UIControlStateNormal];
|
||||
|
||||
// init scrollview content size
|
||||
[_scroll_view setContentSize:[_scroll_view frame].size];
|
||||
|
||||
// set params in the view
|
||||
[_textfield_username setText:[_params valueForKey:@"username"]];
|
||||
[_textfield_password setText:[_params valueForKey:@"password"]];
|
||||
[_textfield_domain setText:[_params valueForKey:@"domain"]];
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
// set signal
|
||||
[[_session uiRequestCompleted] signal];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark iOS Keyboard Notification Handlers
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
CGRect keyboardFrame = [[self view] convertRect:keyboardEndFrame toView:nil];
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
||||
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
|
||||
CGRect frame = [_scroll_view frame];
|
||||
frame.size.height -= keyboardFrame.size.height;
|
||||
[_scroll_view setFrame:frame];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notification
|
||||
{
|
||||
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
CGRect keyboardFrame = [[self view] convertRect:keyboardEndFrame toView:nil];
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
||||
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
|
||||
CGRect frame = [_scroll_view frame];
|
||||
frame.size.height += keyboardFrame.size.height;
|
||||
[_scroll_view setFrame:frame];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Action handlers
|
||||
|
||||
- (IBAction)loginPressed:(id)sender
|
||||
{
|
||||
// read input back in
|
||||
[_params setValue:[_textfield_username text] forKey:@"username"];
|
||||
[_params setValue:[_textfield_password text] forKey:@"password"];
|
||||
[_params setValue:[_textfield_domain text] forKey:@"domain"];
|
||||
[_params setValue:[NSNumber numberWithBool:YES] forKey:@"result"];
|
||||
|
||||
// dismiss controller
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)cancelPressed:(id)sender
|
||||
{
|
||||
[_params setValue:[NSNumber numberWithBool:NO] forKey:@"result"];
|
||||
|
||||
// dismiss controller
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
44
client/iOS/Controllers/EditorBaseController.h
Normal file
44
client/iOS/Controllers/EditorBaseController.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
Basic interface for settings editors
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "EditTextTableViewCell.h"
|
||||
#import "EditFlagTableViewCell.h"
|
||||
#import "EditSelectionTableViewCell.h"
|
||||
#import "EditSubEditTableViewCell.h"
|
||||
#import "EditSecretTextTableViewCell.h"
|
||||
#import "EditButtonTableViewCell.h"
|
||||
|
||||
extern NSString* TableCellIdentifierText;
|
||||
extern NSString* TableCellIdentifierSecretText;
|
||||
extern NSString* TableCellIdentifierYesNo;
|
||||
extern NSString* TableCellIdentifierSelection;
|
||||
extern NSString* TableCellIdentifierSubEditor;
|
||||
extern NSString* TableCellIdentifierMultiChoice;
|
||||
extern NSString* TableCellIdentifierButton;
|
||||
|
||||
@interface EditorBaseController : UITableViewController <UITextFieldDelegate>
|
||||
{
|
||||
@private
|
||||
IBOutlet EditTextTableViewCell* _textTableViewCell;
|
||||
IBOutlet EditSecretTextTableViewCell* _secretTextTableViewCell;
|
||||
IBOutlet EditFlagTableViewCell* _flagTableViewCell;
|
||||
IBOutlet EditSelectionTableViewCell* _selectionTableViewCell;
|
||||
IBOutlet EditSubEditTableViewCell* _subEditTableViewCell;
|
||||
IBOutlet EditButtonTableViewCell* _buttonTableViewCell;
|
||||
}
|
||||
|
||||
// returns one of the requested table view cells
|
||||
- (UITableViewCell*)tableViewCellFromIdentifier:(NSString*)identifier;
|
||||
|
||||
// Adjust text input cells label/textfield widht according to the label's text size
|
||||
- (void)adjustEditTextTableViewCell:(EditTextTableViewCell*)cell;
|
||||
|
||||
@end
|
||||
108
client/iOS/Controllers/EditorBaseController.m
Normal file
108
client/iOS/Controllers/EditorBaseController.m
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
Basic interface for settings editors
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@interface EditorBaseController ()
|
||||
|
||||
@end
|
||||
|
||||
NSString* TableCellIdentifierText = @"cellIdText";
|
||||
NSString* TableCellIdentifierSecretText = @"cellIdSecretText";
|
||||
NSString* TableCellIdentifierYesNo = @"cellIdYesNo";
|
||||
NSString* TableCellIdentifierSelection = @"cellIdSelection";
|
||||
NSString* TableCellIdentifierSubEditor = @"cellIdSubEditor";
|
||||
NSString* TableCellIdentifierMultiChoice = @"cellIdMultiChoice";
|
||||
NSString* TableCellIdentifierButton = @"cellIdButton";
|
||||
|
||||
@implementation EditorBaseController
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Create table view cells
|
||||
- (UITableViewCell*)tableViewCellFromIdentifier:(NSString*)identifier
|
||||
{
|
||||
// try to reuse a cell
|
||||
UITableViewCell* cell = [[self tableView] dequeueReusableCellWithIdentifier:identifier];
|
||||
if (cell != nil)
|
||||
return cell;
|
||||
|
||||
// we have to create a new cell
|
||||
if ([identifier isEqualToString:TableCellIdentifierText])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditTextTableViewCell" owner:self options:nil];
|
||||
cell = _textTableViewCell;
|
||||
_textTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierSecretText])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditSecretTextTableViewCell" owner:self options:nil];
|
||||
cell = _secretTextTableViewCell;
|
||||
_secretTextTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierYesNo])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditFlagTableViewCell" owner:self options:nil];
|
||||
cell = _flagTableViewCell;
|
||||
_flagTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierSelection])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditSelectionTableViewCell" owner:self options:nil];
|
||||
cell = _selectionTableViewCell;
|
||||
_selectionTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierSubEditor])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditSubEditTableViewCell" owner:self options:nil];
|
||||
cell = _subEditTableViewCell;
|
||||
_subEditTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierButton])
|
||||
{
|
||||
[[NSBundle mainBundle] loadNibNamed:@"EditButtonTableViewCell" owner:self options:nil];
|
||||
cell = _buttonTableViewCell;
|
||||
_buttonTableViewCell = nil;
|
||||
}
|
||||
else if ([identifier isEqualToString:TableCellIdentifierMultiChoice])
|
||||
{
|
||||
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:identifier] autorelease];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSAssert(false, @"Unknown table cell identifier");
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Utility functions
|
||||
- (void)adjustEditTextTableViewCell:(EditTextTableViewCell*)cell
|
||||
{
|
||||
UILabel* label = [cell label];
|
||||
UITextField* textField = [cell textfield];
|
||||
|
||||
// adjust label
|
||||
CGFloat width = [[label text] sizeWithFont:[label font]].width;
|
||||
CGRect frame = [label frame];
|
||||
CGFloat delta = width - frame.size.width;
|
||||
frame.size.width = width;
|
||||
[label setFrame:frame];
|
||||
|
||||
// adjust text field
|
||||
frame = [textField frame];
|
||||
frame.origin.x += delta;
|
||||
frame.size.width -= delta;
|
||||
[textField setFrame:frame];
|
||||
}
|
||||
|
||||
@end
|
||||
30
client/iOS/Controllers/EditorSelectionController.h
Normal file
30
client/iOS/Controllers/EditorSelectionController.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Generic controller to select a single item from a list of options
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ConnectionParams;
|
||||
|
||||
@interface EditorSelectionController : EditorBaseController
|
||||
{
|
||||
ConnectionParams* _params;
|
||||
|
||||
// array with entries in connection parameters that are altered
|
||||
NSArray* _entries;
|
||||
|
||||
// array with dictionaries containing label/value pairs that represent the available values for each entry
|
||||
NSArray* _selections;
|
||||
|
||||
// current selections
|
||||
NSMutableArray* _cur_selections;
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params entries:(NSArray*)entries selections:(NSArray*)selections;
|
||||
|
||||
@end
|
||||
136
client/iOS/Controllers/EditorSelectionController.m
Normal file
136
client/iOS/Controllers/EditorSelectionController.m
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
Generic controller to select a single item from a list of options
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "EditorSelectionController.h"
|
||||
#import "ConnectionParams.h"
|
||||
#import "OrderedDictionary.h"
|
||||
|
||||
@interface EditorSelectionController (Private)
|
||||
- (OrderedDictionary*)selectionForIndex:(int)index;
|
||||
@end
|
||||
|
||||
@implementation EditorSelectionController
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params entries:(NSArray *)entries selections:(NSArray *)selections
|
||||
{
|
||||
self = [super initWithStyle:UITableViewStyleGrouped];
|
||||
if (self)
|
||||
{
|
||||
_params = [params retain];
|
||||
_entries = [entries retain];
|
||||
_selections = [selections retain];
|
||||
|
||||
// allocate and init current selections array
|
||||
_cur_selections = [[NSMutableArray alloc] initWithCapacity:[_entries count]];
|
||||
for (int i = 0; i < [entries count]; ++i)
|
||||
{
|
||||
NSString* entry = [entries objectAtIndex:i];
|
||||
if([_params hasValueForKeyPath:entry])
|
||||
{
|
||||
NSUInteger idx = [(OrderedDictionary*)[selections objectAtIndex:i] indexForValue:[NSNumber numberWithInt:[_params intForKeyPath:entry]]];
|
||||
[_cur_selections addObject:[NSNumber numberWithInt:(idx != NSNotFound ? idx : 0)]];
|
||||
}
|
||||
else
|
||||
[_cur_selections addObject:[NSNumber numberWithInt:0]];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning
|
||||
{
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Release any cached data, images, etc that aren't in use.
|
||||
[_params autorelease];
|
||||
[_entries autorelease];
|
||||
[_selections autorelease];
|
||||
[_cur_selections autorelease];
|
||||
}
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
// Return YES for supported orientations
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
// Return the number of sections.
|
||||
return [_entries count];
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
// Return the number of rows in the section.
|
||||
return [[self selectionForIndex:section] count];
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell = [self tableViewCellFromIdentifier:TableCellIdentifierMultiChoice];
|
||||
|
||||
// get selection
|
||||
OrderedDictionary* selection = [self selectionForIndex:[indexPath section]];
|
||||
|
||||
// set cell properties
|
||||
[[cell textLabel] setText:[selection keyAtIndex:[indexPath row]]];
|
||||
|
||||
// set default checkmark
|
||||
if([indexPath row] == [[_cur_selections objectAtIndex:[indexPath section]] intValue])
|
||||
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
|
||||
else
|
||||
[cell setAccessoryType:UITableViewCellAccessoryNone];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
// has selection change?
|
||||
int cur_selection = [[_cur_selections objectAtIndex:[indexPath section]] intValue];
|
||||
if([indexPath row] != cur_selection)
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
|
||||
NSIndexPath* oldIndexPath = [NSIndexPath indexPathForRow:cur_selection inSection:[indexPath section]];
|
||||
|
||||
// clear old checkmark
|
||||
UITableViewCell* old_sel_cell = [tableView cellForRowAtIndexPath:oldIndexPath];
|
||||
old_sel_cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
|
||||
// set new checkmark
|
||||
UITableViewCell* new_sel_cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
new_sel_cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||
|
||||
// get value from selection dictionary
|
||||
OrderedDictionary* dict = [self selectionForIndex:[indexPath section]];
|
||||
int sel_value = [[dict valueForKey:[dict keyAtIndex:[indexPath row]]] intValue];
|
||||
|
||||
// update selection index and params value
|
||||
[_cur_selections replaceObjectAtIndex:[indexPath section] withObject:[NSNumber numberWithInt:[indexPath row]]];
|
||||
[_params setInt:sel_value forKeyPath:[_entries objectAtIndex:[indexPath section]]];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Convenience functions
|
||||
|
||||
- (OrderedDictionary*)selectionForIndex:(int)index
|
||||
{
|
||||
return (OrderedDictionary*)[_selections objectAtIndex:index];
|
||||
}
|
||||
|
||||
@end
|
||||
24
client/iOS/Controllers/EncryptionController.h
Normal file
24
client/iOS/Controllers/EncryptionController.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
Password Encryption Controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Encryptor.h"
|
||||
|
||||
@interface EncryptionController : NSObject
|
||||
{
|
||||
Encryptor* _shared_encryptor;
|
||||
}
|
||||
|
||||
+ (EncryptionController*)sharedEncryptionController;
|
||||
|
||||
// Return a Encryptor suitable for encrypting or decrypting with the master password
|
||||
- (Encryptor*)decryptor;
|
||||
- (Encryptor*)encryptor;
|
||||
|
||||
@end
|
||||
133
client/iOS/Controllers/EncryptionController.m
Normal file
133
client/iOS/Controllers/EncryptionController.m
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
Password Encryption Controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Dorian Johnson
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "EncryptionController.h"
|
||||
#import "SFHFKeychainUtils.h"
|
||||
|
||||
@interface EncryptionController (Private)
|
||||
|
||||
- (BOOL)verifyPassword:(Encryptor*)decryptor;
|
||||
- (NSData*)encryptedVerificationData;
|
||||
- (void)setEncryptedVerificationData:(Encryptor*)encryptor;
|
||||
|
||||
- (NSString*)keychainServerName;
|
||||
- (NSString*)keychainUsername;
|
||||
- (void)setKeychainPassword:(NSString*)password;
|
||||
- (NSString*)keychainPassword;
|
||||
- (NSString*)keychainDefaultPassword;
|
||||
|
||||
@end
|
||||
|
||||
static EncryptionController* _shared_encryption_controller = nil;
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation EncryptionController
|
||||
|
||||
+ (EncryptionController*)sharedEncryptionController
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
if (_shared_encryption_controller == nil)
|
||||
_shared_encryption_controller = [[EncryptionController alloc] init];
|
||||
}
|
||||
|
||||
return _shared_encryption_controller;
|
||||
}
|
||||
|
||||
#pragma mark Getting an encryptor or decryptor
|
||||
|
||||
- (Encryptor*)encryptor
|
||||
{
|
||||
if (_shared_encryptor)
|
||||
return _shared_encryptor;
|
||||
|
||||
NSString* saved_password = [self keychainPassword];
|
||||
if (saved_password == nil)
|
||||
{
|
||||
saved_password = [self keychainDefaultPassword];
|
||||
Encryptor* encryptor = [[[Encryptor alloc] initWithPassword:saved_password] autorelease];
|
||||
[self setEncryptedVerificationData:encryptor];
|
||||
_shared_encryptor = [encryptor retain];
|
||||
}
|
||||
else
|
||||
{
|
||||
Encryptor* encryptor = [[[Encryptor alloc] initWithPassword:saved_password] autorelease];
|
||||
if ([self verifyPassword:encryptor])
|
||||
_shared_encryptor = [encryptor retain];
|
||||
}
|
||||
|
||||
return _shared_encryptor;
|
||||
}
|
||||
|
||||
// For the current implementation, decryptors and encryptors are equivilant.
|
||||
- (Encryptor*)decryptor { return [self encryptor]; }
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation EncryptionController (Private)
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Keychain password storage
|
||||
|
||||
- (NSString*)keychainServerName
|
||||
{
|
||||
return [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleName"];
|
||||
}
|
||||
|
||||
- (NSString*)keychainUsername
|
||||
{
|
||||
return @"master.password";
|
||||
}
|
||||
|
||||
- (void)setKeychainPassword:(NSString*)password
|
||||
{
|
||||
NSError* error;
|
||||
if (password == nil)
|
||||
{
|
||||
[SFHFKeychainUtils deleteItemForUsername:[self keychainUsername] andServerName:[self keychainServerName] error:&error];
|
||||
return;
|
||||
}
|
||||
|
||||
[SFHFKeychainUtils storeUsername:[self keychainUsername] andPassword:password forServerName:[self keychainServerName] updateExisting:YES error:&error];
|
||||
}
|
||||
|
||||
- (NSString*)keychainPassword
|
||||
{
|
||||
NSError* error;
|
||||
return [SFHFKeychainUtils getPasswordForUsername:[self keychainUsername] andServerName:[self keychainServerName] error:&error];
|
||||
}
|
||||
|
||||
- (NSString*)keychainDefaultPassword
|
||||
{
|
||||
return [[UIDevice currentDevice] uniqueIdentifier];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Verification of encryption key against verification data
|
||||
|
||||
- (BOOL)verifyPassword:(Encryptor*)decryptor
|
||||
{
|
||||
return [[decryptor plaintextPassword] isEqualToString:[decryptor decryptString:[self encryptedVerificationData]]];
|
||||
}
|
||||
|
||||
- (NSData*)encryptedVerificationData
|
||||
{
|
||||
return [[NSUserDefaults standardUserDefaults] dataForKey:@"TSXMasterPasswordVerification"];
|
||||
}
|
||||
|
||||
- (void)setEncryptedVerificationData:(Encryptor*)encryptor
|
||||
{
|
||||
[[NSUserDefaults standardUserDefaults] setObject:[encryptor encryptString:[encryptor plaintextPassword]] forKey:@"TSXMasterPasswordVerification"];
|
||||
}
|
||||
|
||||
@end
|
||||
16
client/iOS/Controllers/HelpController.h
Normal file
16
client/iOS/Controllers/HelpController.h
Normal file
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
Application help controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface HelpController : UIViewController <UIWebViewDelegate>
|
||||
{
|
||||
UIWebView* webView;
|
||||
}
|
||||
@end
|
||||
81
client/iOS/Controllers/HelpController.m
Normal file
81
client/iOS/Controllers/HelpController.m
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Application help controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "HelpController.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@implementation HelpController
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
// set title and tab-bar image
|
||||
[self setTitle:NSLocalizedString(@"Help", @"Help Controller title")];
|
||||
UIImage* tabBarIcon = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tabbar_icon_help" ofType:@"png"]];
|
||||
[self setTabBarItem:[[UITabBarItem alloc] initWithTitle:NSLocalizedString(@"Help", @"Tabbar item help") image:tabBarIcon tag:0]];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
// Implement loadView to create a view hierarchy programmatically, without using a nib.
|
||||
- (void)loadView
|
||||
{
|
||||
webView = [[[UIWebView alloc] initWithFrame:CGRectZero] autorelease];
|
||||
[webView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
|
||||
[webView setAutoresizesSubviews:YES];
|
||||
[webView setDelegate:self];
|
||||
[webView setDataDetectorTypes:UIDataDetectorTypeNone];
|
||||
[self setView:webView];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
NSString *filename = (IsPhone() ? @"gestures_phone" : @"gestures");
|
||||
NSString *htmlString = [[[NSString alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:filename ofType:@"html" inDirectory:@"help_page"] encoding:NSUTF8StringEncoding error:nil] autorelease];
|
||||
|
||||
[webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"help_page"]]];
|
||||
}
|
||||
|
||||
// Override to allow orientations other than the default portrait orientation.
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark UIWebView callbacks
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
|
||||
{
|
||||
if([[request URL] isFileURL])
|
||||
return YES;
|
||||
|
||||
if(navigationType == UIWebViewNavigationTypeLinkClicked)
|
||||
{
|
||||
NSString* lastClickedLink = [[request URL] absoluteString];
|
||||
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"External Link"
|
||||
message:[NSString stringWithFormat:@"Open [%@] in Browser?", lastClickedLink]
|
||||
delegate:self
|
||||
cancelButtonTitle:@"OK"
|
||||
otherButtonTitles:@"No", nil];
|
||||
[alert show];
|
||||
[alert release];
|
||||
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
17
client/iOS/Controllers/MainTabBarController.h
Normal file
17
client/iOS/Controllers/MainTabBarController.h
Normal file
@@ -0,0 +1,17 @@
|
||||
/*
|
||||
main tabbar controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
|
||||
@interface MainTabBarController : UITabBarController {
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
20
client/iOS/Controllers/MainTabBarController.m
Normal file
20
client/iOS/Controllers/MainTabBarController.m
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
main tabbar controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "MainTabBarController.h"
|
||||
|
||||
|
||||
@implementation MainTabBarController
|
||||
|
||||
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
24
client/iOS/Controllers/PerformanceEditorController.h
Normal file
24
client/iOS/Controllers/PerformanceEditorController.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
controller for performance settings selection
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ConnectionParams;
|
||||
|
||||
@interface PerformanceEditorController : EditorBaseController
|
||||
{
|
||||
@private
|
||||
ConnectionParams* _params;
|
||||
NSString* _keyPath;
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params;
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:(NSString*)keyPath;
|
||||
|
||||
@end
|
||||
187
client/iOS/Controllers/PerformanceEditorController.m
Normal file
187
client/iOS/Controllers/PerformanceEditorController.m
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
controller for performance settings selection
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "PerformanceEditorController.h"
|
||||
#import "ConnectionParams.h"
|
||||
#import "Utils.h"
|
||||
|
||||
@interface PerformanceEditorController (Private)
|
||||
-(NSString*)keyPathForKey:(NSString*)key;
|
||||
@end
|
||||
|
||||
@implementation PerformanceEditorController
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params
|
||||
{
|
||||
return [self initWithConnectionParams:params keyPath:nil];
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:(NSString*)keyPath;
|
||||
{
|
||||
self = [super initWithStyle:UITableViewStyleGrouped];
|
||||
if (self) {
|
||||
_params = [params retain];
|
||||
_keyPath = (keyPath != nil ? [keyPath retain] : nil);
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
// Do any additional setup after loading the view.
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(NSString*)keyPathForKey:(NSString*)key
|
||||
{
|
||||
if (_keyPath)
|
||||
return [_keyPath stringByAppendingFormat:@".%@", key];
|
||||
return key;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
|
||||
// Return the number of sections.
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
|
||||
return 7;
|
||||
}
|
||||
|
||||
|
||||
// set section headers
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
return NSLocalizedString(@"Performance Settings", @"'Performance Settings': performance settings header");
|
||||
}
|
||||
|
||||
// Customize the appearance of table view cells.
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
|
||||
|
||||
// get the table view cell
|
||||
EditFlagTableViewCell *cell = (EditFlagTableViewCell*)[self tableViewCellFromIdentifier:TableCellIdentifierYesNo];
|
||||
NSAssert(cell, @"Invalid cell");
|
||||
|
||||
switch ([indexPath row])
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"RemoteFX", @"RemoteFX performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_remotefx"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Desktop Background", @"Desktop background performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_show_desktop"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 2:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Font Smoothing", @"Font smoothing performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_font_smoothing"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Desktop Composition", @"Desktop composition performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_desktop_composition"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 4:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Window contents while dragging", @"Window Dragging performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_window_dragging"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 5:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Menu Animation", @"Menu Animations performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_menu_animation"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
case 6:
|
||||
{
|
||||
[[cell label] setText:NSLocalizedString(@"Visual Styles", @"Use Themes performance setting")];
|
||||
[[cell toggle] setOn:[_params boolForKeyPath:[self keyPathForKey:@"perf_windows_themes"]]];
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
[[cell toggle] setTag:GET_TAG_FROM_PATH(indexPath)];
|
||||
[[cell toggle] addTarget:self action:@selector(togglePerformanceSetting:) forControlEvents:UIControlEventValueChanged];
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Action Handlers
|
||||
|
||||
- (void)togglePerformanceSetting:(id)sender
|
||||
{
|
||||
UISwitch* valueSwitch = (UISwitch*)sender;
|
||||
switch(valueSwitch.tag)
|
||||
{
|
||||
case GET_TAG(0, 0):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_remotefx"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 1):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_show_desktop"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 2):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_font_smoothing"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 3):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_desktop_composition"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 4):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_window_dragging"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 5):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_menu_animation"]];
|
||||
break;
|
||||
|
||||
case GET_TAG(0, 6):
|
||||
[_params setBool:[valueSwitch isOn] forKeyPath:[self keyPathForKey:@"perf_windows_themes"]];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
69
client/iOS/Controllers/RDPSessionViewController.h
Normal file
69
client/iOS/Controllers/RDPSessionViewController.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
RDP Session View Controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "RDPSession.h"
|
||||
#import "RDPKeyboard.h"
|
||||
#import "RDPSessionView.h"
|
||||
#import "TouchPointerView.h"
|
||||
#import "AdvancedKeyboardView.h"
|
||||
|
||||
@interface RDPSessionViewController : UIViewController <RDPSessionDelegate, TouchPointerDelegate, AdvancedKeyboardDelegate, RDPKeyboardDelegate, UIScrollViewDelegate, UITextFieldDelegate, UIAlertViewDelegate>
|
||||
{
|
||||
// scrollview that hosts the rdp session view
|
||||
IBOutlet UIScrollView* _session_scrollview;
|
||||
|
||||
// rdp session view
|
||||
IBOutlet RDPSessionView* _session_view;
|
||||
|
||||
// touch pointer view
|
||||
IBOutlet TouchPointerView* _touchpointer_view;
|
||||
BOOL _autoscroll_with_touchpointer;
|
||||
BOOL _is_autoscrolling;
|
||||
|
||||
// rdp session toolbar
|
||||
IBOutlet UIToolbar* _session_toolbar;
|
||||
BOOL _session_toolbar_visible;
|
||||
|
||||
// dummy text field used to display the keyboard
|
||||
IBOutlet UITextField* _dummy_textfield;
|
||||
|
||||
// connecting view and the controls within that view
|
||||
IBOutlet UIView* _connecting_view;
|
||||
IBOutlet UILabel* _lbl_connecting;
|
||||
IBOutlet UIActivityIndicatorView* _connecting_indicator_view;
|
||||
IBOutlet UIButton* _cancel_connect_button;
|
||||
|
||||
// extended keyboard toolbar
|
||||
UIToolbar* _keyboard_toolbar;
|
||||
|
||||
// rdp session
|
||||
RDPSession* _session;
|
||||
BOOL _session_initilized;
|
||||
|
||||
// flag that indicates whether the keyboard is visible or not
|
||||
BOOL _keyboard_visible;
|
||||
|
||||
// flag to switch between left/right mouse button mode
|
||||
BOOL _toggle_mouse_button;
|
||||
|
||||
// keyboard extension view
|
||||
AdvancedKeyboardView* _advanced_keyboard_view;
|
||||
BOOL _advanced_keyboard_visible;
|
||||
BOOL _requesting_advanced_keyboard;
|
||||
|
||||
// delayed mouse move event sending
|
||||
NSTimer* _mouse_move_event_timer;
|
||||
int _mouse_move_events_skipped;
|
||||
CGPoint _prev_long_press_position;
|
||||
}
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession*)session;
|
||||
|
||||
@end
|
||||
980
client/iOS/Controllers/RDPSessionViewController.m
Normal file
980
client/iOS/Controllers/RDPSessionViewController.m
Normal file
@@ -0,0 +1,980 @@
|
||||
/*
|
||||
RDP Session View Controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#import "RDPSessionViewController.h"
|
||||
#import "RDPKeyboard.h"
|
||||
#import "Utils.h"
|
||||
#import "Toast+UIView.h"
|
||||
#import "ConnectionParams.h"
|
||||
#import "CredentialsInputController.h"
|
||||
#import "VerifyCertificateController.h"
|
||||
|
||||
#define TOOLBAR_HEIGHT 30
|
||||
|
||||
#define AUTOSCROLLDISTANCE 20
|
||||
#define AUTOSCROLLTIMEOUT 0.05
|
||||
|
||||
@interface RDPSessionViewController (Private)
|
||||
-(void)showSessionToolbar:(BOOL)show;
|
||||
-(UIToolbar*)keyboardToolbar;
|
||||
-(void)initGestureRecognizers;
|
||||
- (void)suspendSession;
|
||||
- (NSDictionary*)eventDescriptorForMouseEvent:(int)event position:(CGPoint)position;
|
||||
- (void)handleMouseMoveForPosition:(CGPoint)position;
|
||||
@end
|
||||
|
||||
|
||||
@implementation RDPSessionViewController
|
||||
|
||||
#pragma mark class methods
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession *)session
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self)
|
||||
{
|
||||
_session = [session retain];
|
||||
[_session setDelegate:self];
|
||||
_session_initilized = NO;
|
||||
|
||||
_mouse_move_events_skipped = 0;
|
||||
_mouse_move_event_timer = nil;
|
||||
|
||||
_advanced_keyboard_view = nil;
|
||||
_advanced_keyboard_visible = NO;
|
||||
_requesting_advanced_keyboard = NO;
|
||||
|
||||
_session_toolbar_visible = NO;
|
||||
|
||||
_toggle_mouse_button = NO;
|
||||
|
||||
_autoscroll_with_touchpointer = [[NSUserDefaults standardUserDefaults] boolForKey:@"ui.auto_scroll_touchpointer"];
|
||||
_is_autoscrolling = NO;
|
||||
|
||||
[UIView setAnimationDelegate:self];
|
||||
[UIView setAnimationDidStopSelector:@selector(animationStopped:finished:context:)];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
// Implement loadView to create a view hierarchy programmatically, without using a nib.
|
||||
- (void)loadView
|
||||
{
|
||||
// load default view and set background color and resizing mask
|
||||
[super loadView];
|
||||
|
||||
// init keyboard handling vars and register required notification handlers
|
||||
_keyboard_visible = NO;
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name: UIKeyboardWillShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name: UIKeyboardDidShowNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name: UIKeyboardWillHideNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidHide:) name: UIKeyboardDidHideNotification object:nil];
|
||||
|
||||
// init keyboard toolbar
|
||||
_keyboard_toolbar = [[self keyboardToolbar] retain];
|
||||
[_dummy_textfield setInputAccessoryView:_keyboard_toolbar];
|
||||
|
||||
// init gesture recognizers
|
||||
[self initGestureRecognizers];
|
||||
|
||||
// hide session toolbar
|
||||
[_session_toolbar setFrame:CGRectMake(0.0, -TOOLBAR_HEIGHT, [[self view] bounds].size.width, TOOLBAR_HEIGHT)];
|
||||
}
|
||||
|
||||
|
||||
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
|
||||
{
|
||||
if (![_touchpointer_view isHidden])
|
||||
[_touchpointer_view ensurePointerIsVisible];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
// Releases the view if it doesn't have a superview.
|
||||
[super didReceiveMemoryWarning];
|
||||
|
||||
// Release any cached data, images, etc. that aren't in use.
|
||||
}
|
||||
|
||||
- (void)viewDidUnload {
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
// e.g. self.myOutlet = nil;
|
||||
}
|
||||
|
||||
- (void)viewWillAppear:(BOOL)animated
|
||||
{
|
||||
[super viewWillAppear:animated];
|
||||
|
||||
// hide navigation bar and (if enabled) the status bar
|
||||
if ([[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_status_bar"])
|
||||
{
|
||||
if(animated == YES)
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
|
||||
else
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationNone];
|
||||
}
|
||||
[[self navigationController] setNavigationBarHidden:YES animated:animated];
|
||||
|
||||
// if sesssion is suspended - notify that we got a new bitmap context
|
||||
if ([_session isSuspended])
|
||||
[self sessionBitmapContextWillChange:_session];
|
||||
|
||||
// init keyboard
|
||||
[[RDPKeyboard getSharedRDPKeyboard] initWithSession:_session delegate:self];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
if (!_session_initilized)
|
||||
{
|
||||
if ([_session isSuspended])
|
||||
{
|
||||
[_session resume];
|
||||
[self sessionBitmapContextDidChange:_session];
|
||||
[_session_view setNeedsDisplay];
|
||||
}
|
||||
else
|
||||
[_session connect];
|
||||
|
||||
_session_initilized = YES;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewWillDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewWillDisappear:animated];
|
||||
|
||||
// show navigation and status bar again
|
||||
if(animated == YES)
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
|
||||
else
|
||||
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
|
||||
[[self navigationController] setNavigationBarHidden:NO animated:animated];
|
||||
|
||||
// reset all modifier keys on rdp keyboard
|
||||
[[RDPKeyboard getSharedRDPKeyboard] reset];
|
||||
|
||||
// hide toolbar and keyboard
|
||||
[self showSessionToolbar:NO];
|
||||
[_dummy_textfield resignFirstResponder];
|
||||
}
|
||||
|
||||
|
||||
- (void)dealloc {
|
||||
// remove any observers
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
|
||||
// the session lives on longer so set the delegate to nil
|
||||
[_session setDelegate:nil];
|
||||
|
||||
[_advanced_keyboard_view release];
|
||||
[_keyboard_toolbar release];
|
||||
[_session release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark ScrollView delegate methods
|
||||
|
||||
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView
|
||||
{
|
||||
return _session_view;
|
||||
}
|
||||
|
||||
-(void)scrollViewDidEndZooming:(UIScrollView *)scrollView withView:(UIView *)view atScale:(float)scale
|
||||
{
|
||||
NSLog(@"New zoom scale: %f", scale);
|
||||
[_session_view setNeedsDisplay];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark TextField delegate methods
|
||||
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
|
||||
{
|
||||
_keyboard_visible = YES;
|
||||
_advanced_keyboard_visible = NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
-(BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
_keyboard_visible = NO;
|
||||
_advanced_keyboard_visible = NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
|
||||
{
|
||||
if([string length] > 0)
|
||||
{
|
||||
for(int i = 0 ; i < [string length] ; i++)
|
||||
{
|
||||
NSString *characterTyped = [string substringWithRange:NSMakeRange(i, 1)];
|
||||
unichar curChar = [characterTyped characterAtIndex:0];
|
||||
|
||||
// special handling for return/enter key
|
||||
if(curChar == '\n')
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendEnterKeyStroke];
|
||||
else
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendUnicode:curChar];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendBackspaceKeyStroke];
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark AdvancedKeyboardDelegate functions
|
||||
-(void)advancedKeyPressedVKey:(int)key
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendVirtualKeyCode:key];
|
||||
}
|
||||
|
||||
-(void)advancedKeyPressedUnicode:(int)key
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendUnicode:key];
|
||||
}
|
||||
|
||||
#pragma mark - RDP keyboard handler
|
||||
|
||||
- (void)modifiersChangedForKeyboard:(RDPKeyboard *)keyboard
|
||||
{
|
||||
UIBarButtonItem* curItem;
|
||||
|
||||
// shift button (only on iPad)
|
||||
int objectIdx = 0;
|
||||
if (IsPad())
|
||||
{
|
||||
objectIdx = 2;
|
||||
curItem = (UIBarButtonItem*)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
|
||||
[curItem setStyle:[keyboard shiftPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
|
||||
}
|
||||
|
||||
// ctrl button
|
||||
objectIdx += 2;
|
||||
curItem = (UIBarButtonItem*)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
|
||||
[curItem setStyle:[keyboard ctrlPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
|
||||
|
||||
// win button
|
||||
objectIdx += 2;
|
||||
curItem = (UIBarButtonItem*)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
|
||||
[curItem setStyle:[keyboard winPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
|
||||
|
||||
// alt button
|
||||
objectIdx += 2;
|
||||
curItem = (UIBarButtonItem*)[[_keyboard_toolbar items] objectAtIndex:objectIdx];
|
||||
[curItem setStyle:[keyboard altPressed] ? UIBarButtonItemStyleDone : UIBarButtonItemStyleBordered];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark RDPSessionDelegate functions
|
||||
|
||||
- (void)session:(RDPSession*)session didFailToConnect:(int)reason
|
||||
{
|
||||
// remove and release connecting view
|
||||
[_connecting_indicator_view stopAnimating];
|
||||
[_connecting_view removeFromSuperview];
|
||||
[_connecting_view autorelease];
|
||||
|
||||
// return to bookmark list
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)sessionWillConnect:(RDPSession*)session
|
||||
{
|
||||
// load connecting view
|
||||
[[NSBundle mainBundle] loadNibNamed:@"RDPConnectingView" owner:self options:nil];
|
||||
|
||||
// set strings
|
||||
[_lbl_connecting setText:NSLocalizedString(@"Connecting", @"Connecting progress view - label")];
|
||||
[_cancel_connect_button setTitle:NSLocalizedString(@"Cancel", @"Cancel Button") forState:UIControlStateNormal];
|
||||
|
||||
// center view and give it round corners
|
||||
[_connecting_view setCenter:[[self view] center]];
|
||||
[[_connecting_view layer] setCornerRadius:10];
|
||||
|
||||
// display connecting view and start indicator
|
||||
[[self view] addSubview:_connecting_view];
|
||||
[_connecting_indicator_view startAnimating];
|
||||
}
|
||||
|
||||
- (void)sessionDidConnect:(RDPSession*)session
|
||||
{
|
||||
// remove and release connecting view
|
||||
[_connecting_indicator_view stopAnimating];
|
||||
[_connecting_view removeFromSuperview];
|
||||
[_connecting_view autorelease];
|
||||
|
||||
// check if session settings changed ...
|
||||
// The 2nd width check is to ignore changes in resolution settings due to the RDVH display bug (refer to RDPSEssion.m for more details)
|
||||
ConnectionParams* orig_params = [session params];
|
||||
rdpSettings* sess_params = [session getSessionParams];
|
||||
if (([orig_params intForKey:@"width"] != sess_params->DesktopWidth && [orig_params intForKey:@"width"] != (sess_params->DesktopWidth + 1)) ||
|
||||
[orig_params intForKey:@"height"] != sess_params->DesktopHeight || [orig_params intForKey:@"colors"] != sess_params->ColorDepth)
|
||||
{
|
||||
// display notification that the session params have been changed by the server
|
||||
NSString* message = [NSString stringWithFormat:NSLocalizedString(@"The server changed the screen settings to %dx%dx%d", @"Screen settings not supported message with width, height and colors parameter"), sess_params->DesktopWidth, sess_params->DesktopHeight, sess_params->ColorDepth];
|
||||
[[self view] makeToast:message duration:ToastDurationNormal position:@"bottom"];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)sessionWillDisconnect:(RDPSession*)session
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
- (void)sessionDidDisconnect:(RDPSession*)session
|
||||
{
|
||||
// return to bookmark list
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)sessionBitmapContextWillChange:(RDPSession*)session
|
||||
{
|
||||
// calc new view frame
|
||||
rdpSettings* sess_params = [session getSessionParams];
|
||||
CGRect view_rect = CGRectMake(0, 0, sess_params->DesktopWidth, sess_params->DesktopHeight);
|
||||
|
||||
// reset zoom level and update content size
|
||||
[_session_scrollview setZoomScale:1.0];
|
||||
[_session_scrollview setContentSize:view_rect.size];
|
||||
|
||||
// set session view size
|
||||
[_session_view setFrame:view_rect];
|
||||
|
||||
// show/hide toolbar
|
||||
[_session setToolbarVisible:![[NSUserDefaults standardUserDefaults] boolForKey:@"ui.hide_tool_bar"]];
|
||||
[self showSessionToolbar:[_session toolbarVisible]];
|
||||
}
|
||||
|
||||
- (void)sessionBitmapContextDidChange:(RDPSession*)session
|
||||
{
|
||||
// associate view with session
|
||||
[_session_view setSession:session];
|
||||
}
|
||||
|
||||
- (void)session:(RDPSession*)session needsRedrawInRect:(CGRect)rect
|
||||
{
|
||||
[_session_view setNeedsDisplayInRect:rect];
|
||||
}
|
||||
|
||||
- (void)session:(RDPSession *)session requestsAuthenticationWithParams:(NSMutableDictionary *)params
|
||||
{
|
||||
CredentialsInputController* view_controller = [[[CredentialsInputController alloc] initWithNibName:@"CredentialsInputView" bundle:nil session:_session params:params] autorelease];
|
||||
[self presentModalViewController:view_controller animated:YES];
|
||||
}
|
||||
|
||||
- (void)session:(RDPSession *)session verifyCertificateWithParams:(NSMutableDictionary *)params
|
||||
{
|
||||
VerifyCertificateController* view_controller = [[[VerifyCertificateController alloc] initWithNibName:@"VerifyCertificateView" bundle:nil session:_session params:params] autorelease];
|
||||
[self presentModalViewController:view_controller animated:YES];
|
||||
}
|
||||
|
||||
- (CGSize)sizeForFitScreenForSession:(RDPSession*)session
|
||||
{
|
||||
if (IsPad())
|
||||
return [self view].bounds.size;
|
||||
else
|
||||
{
|
||||
// on phones make a resolution that has a 16:10 ratio with the phone's height
|
||||
CGSize size = [self view].bounds.size;
|
||||
CGFloat maxSize = (size.width > size.height) ? size.width : size.height;
|
||||
return CGSizeMake(maxSize * 1.6f, maxSize);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showGoProScreen:(RDPSession*)session
|
||||
{
|
||||
UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Pro Version", @"Pro version dialog title")
|
||||
message:NSLocalizedString(@"Do you want to buy Thinstuff RDC Pro and enable the full RDP Experience", @"Pro version dialog message") delegate:self cancelButtonTitle:NSLocalizedString(@"No", @"No Button title") otherButtonTitles:NSLocalizedString(@"Yes", @"Yes button title"), nil] autorelease];
|
||||
[alertView show];
|
||||
}
|
||||
|
||||
#pragma mark - Keyboard Toolbar Handlers
|
||||
|
||||
-(void)showAdvancedKeyboardAnimated
|
||||
{
|
||||
// calc initial and final rect of the advanced keyboard view
|
||||
CGRect rect = [[_keyboard_toolbar superview] bounds];
|
||||
rect.origin.y = [_keyboard_toolbar bounds].size.height;
|
||||
rect.size.height -= rect.origin.y;
|
||||
|
||||
// create new view (hidden) and add to host-view of keyboard toolbar
|
||||
_advanced_keyboard_view = [[AdvancedKeyboardView alloc] initWithFrame:CGRectMake(rect.origin.x,
|
||||
[[_keyboard_toolbar superview] bounds].size.height,
|
||||
rect.size.width, rect.size.height) delegate:self];
|
||||
[[_keyboard_toolbar superview] addSubview:_advanced_keyboard_view];
|
||||
// we set autoresize to YES for the keyboard toolbar's superview so that our adv. keyboard view gets properly resized
|
||||
[[_keyboard_toolbar superview] setAutoresizesSubviews:YES];
|
||||
|
||||
// show view with animation
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[_advanced_keyboard_view setFrame:rect];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
-(IBAction)toggleKeyboardWhenOtherVisible:(id)sender
|
||||
{
|
||||
if(_advanced_keyboard_visible == NO)
|
||||
{
|
||||
[self showAdvancedKeyboardAnimated];
|
||||
}
|
||||
else
|
||||
{
|
||||
// hide existing view
|
||||
[UIView beginAnimations:@"hide_advanced_keyboard_view" context:NULL];
|
||||
CGRect rect = [_advanced_keyboard_view frame];
|
||||
rect.origin.y = [[_keyboard_toolbar superview] bounds].size.height;
|
||||
[_advanced_keyboard_view setFrame:rect];
|
||||
[UIView commitAnimations];
|
||||
|
||||
// the view is released in the animationDidStop selector registered in init
|
||||
}
|
||||
|
||||
// toggle flag
|
||||
_advanced_keyboard_visible = !_advanced_keyboard_visible;
|
||||
}
|
||||
|
||||
-(IBAction)toggleWinKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] toggleWinKey];
|
||||
}
|
||||
|
||||
-(IBAction)toggleShiftKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] toggleShiftKey];
|
||||
}
|
||||
|
||||
-(IBAction)toggleCtrlKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] toggleCtrlKey];
|
||||
}
|
||||
|
||||
-(IBAction)toggleAltKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] toggleAltKey];
|
||||
}
|
||||
|
||||
-(IBAction)pressEscKey:(id)sender
|
||||
{
|
||||
[[RDPKeyboard getSharedRDPKeyboard] sendEscapeKeyStroke];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark event handlers
|
||||
|
||||
- (void)animationStopped:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context
|
||||
{
|
||||
if ([animationID isEqualToString:@"hide_advanced_keyboard_view"])
|
||||
{
|
||||
// cleanup advanced keyboard view
|
||||
[_advanced_keyboard_view removeFromSuperview];
|
||||
[_advanced_keyboard_view autorelease];
|
||||
_advanced_keyboard_view = nil;
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)switchSession:(id)sender
|
||||
{
|
||||
[self suspendSession];
|
||||
}
|
||||
|
||||
- (IBAction)toggleKeyboard:(id)sender
|
||||
{
|
||||
if(!_keyboard_visible)
|
||||
[_dummy_textfield becomeFirstResponder];
|
||||
else
|
||||
[_dummy_textfield resignFirstResponder];
|
||||
}
|
||||
|
||||
- (IBAction)toggleExtKeyboard:(id)sender
|
||||
{
|
||||
// if the sys kb is shown but not the advanced kb then toggle the advanced kb
|
||||
if(_keyboard_visible && !_advanced_keyboard_visible)
|
||||
[self toggleKeyboardWhenOtherVisible:nil];
|
||||
else
|
||||
{
|
||||
// if not visible request the advanced keyboard view
|
||||
if(_advanced_keyboard_visible == NO)
|
||||
_requesting_advanced_keyboard = YES;
|
||||
[self toggleKeyboard:nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)toggleTouchPointer:(id)sender
|
||||
{
|
||||
BOOL toggle_visibilty = ![_touchpointer_view isHidden];
|
||||
[_touchpointer_view setHidden:toggle_visibilty];
|
||||
if(toggle_visibilty)
|
||||
[_session_scrollview setContentInset:UIEdgeInsetsZero];
|
||||
else
|
||||
[_session_scrollview setContentInset:[_touchpointer_view getEdgeInsets]];
|
||||
}
|
||||
|
||||
- (IBAction)disconnectSession:(id)sender
|
||||
{
|
||||
[_session disconnect];
|
||||
}
|
||||
|
||||
|
||||
-(IBAction)cancelButtonPressed:(id)sender
|
||||
{
|
||||
[_session disconnect];
|
||||
}
|
||||
|
||||
#pragma mark In-App purchase transaction notification handlers
|
||||
|
||||
- (void)onTransactionSuccess:(NSNotification*)notification
|
||||
{
|
||||
UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transaction Succeeded", @"Pro version bought dialog title")
|
||||
message:NSLocalizedString(@"Thanks for buying Thinstuff RDC Pro. In order for the purchase to take effect please reconnect your current session.", @"Pro version bought dialog message") delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"OK Button title") otherButtonTitles:nil] autorelease];
|
||||
[alertView show];
|
||||
}
|
||||
|
||||
- (void)onTransactionFailed:(NSNotification*)notification
|
||||
{
|
||||
UIAlertView* alertView = [[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Transaction Failed", @"Pro version buy failed dialog title")
|
||||
message:NSLocalizedString(@"The transaction did not complete successfully!", @"Pro version buy failed dialog message") delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"OK Button title") otherButtonTitles:nil] autorelease];
|
||||
[alertView show];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark iOS Keyboard Notification Handlers
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
||||
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
|
||||
CGRect frame = [_session_scrollview frame];
|
||||
frame.size.height -= [[self view] convertRect:keyboardEndFrame toView:nil].size.height;
|
||||
[_session_scrollview setFrame:frame];
|
||||
[_touchpointer_view setFrame:frame];
|
||||
[UIView commitAnimations];
|
||||
|
||||
[_touchpointer_view ensurePointerIsVisible];
|
||||
}
|
||||
|
||||
- (void)keyboardDidShow:(NSNotification *)notification
|
||||
{
|
||||
if(_requesting_advanced_keyboard)
|
||||
{
|
||||
[self showAdvancedKeyboardAnimated];
|
||||
_advanced_keyboard_visible = YES;
|
||||
_requesting_advanced_keyboard = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)keyboardWillHide:(NSNotification *)notification
|
||||
{
|
||||
CGRect keyboardEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationCurve:[[[notification userInfo] objectForKey:UIKeyboardAnimationCurveUserInfoKey] intValue]];
|
||||
[UIView setAnimationDuration:[[[notification userInfo] objectForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue]];
|
||||
CGRect frame = [_session_scrollview frame];
|
||||
frame.size.height += [[self view] convertRect:keyboardEndFrame toView:nil].size.height;
|
||||
[_session_scrollview setFrame:frame];
|
||||
[_touchpointer_view setFrame:frame];
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
- (void)keyboardDidHide:(NSNotification*)notification
|
||||
{
|
||||
// release adanced keyboard view
|
||||
if(_advanced_keyboard_visible == YES)
|
||||
{
|
||||
_advanced_keyboard_visible = NO;
|
||||
[_advanced_keyboard_view removeFromSuperview];
|
||||
[_advanced_keyboard_view autorelease];
|
||||
_advanced_keyboard_view = nil;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Gesture handlers
|
||||
|
||||
- (void)handleSingleTap:(UITapGestureRecognizer*)gesture
|
||||
{
|
||||
CGPoint pos = [gesture locationInView:_session_view];
|
||||
if (_toggle_mouse_button)
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetRightMouseButtonClickEvent(YES) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetRightMouseButtonClickEvent(NO) position:pos]];
|
||||
}
|
||||
else
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO) position:pos]];
|
||||
}
|
||||
|
||||
_toggle_mouse_button = NO;
|
||||
}
|
||||
|
||||
- (void)handleDoubleTap:(UITapGestureRecognizer*)gesture
|
||||
{
|
||||
CGPoint pos = [gesture locationInView:_session_view];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES) position:pos]];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO) position:pos]];
|
||||
_toggle_mouse_button = NO;
|
||||
}
|
||||
|
||||
- (void)handleLongPress:(UILongPressGestureRecognizer*)gesture
|
||||
{
|
||||
CGPoint pos = [gesture locationInView:_session_view];
|
||||
|
||||
if([gesture state] == UIGestureRecognizerStateBegan)
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(YES) position:pos]];
|
||||
else if([gesture state] == UIGestureRecognizerStateChanged)
|
||||
[self handleMouseMoveForPosition:pos];
|
||||
else if([gesture state] == UIGestureRecognizerStateEnded)
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(NO) position:pos]];
|
||||
}
|
||||
|
||||
|
||||
- (void)handleDoubleLongPress:(UILongPressGestureRecognizer*)gesture
|
||||
{
|
||||
// this point is mapped against the scroll view because we want to have relative movement to the screen/scrollview
|
||||
CGPoint pos = [gesture locationInView:_session_scrollview];
|
||||
|
||||
if([gesture state] == UIGestureRecognizerStateBegan)
|
||||
_prev_long_press_position = pos;
|
||||
else if([gesture state] == UIGestureRecognizerStateChanged)
|
||||
{
|
||||
int delta = _prev_long_press_position.y - pos.y;
|
||||
|
||||
if(delta > GetScrollGestureDelta())
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetMouseWheelEvent(YES) position:pos]];
|
||||
_prev_long_press_position = pos;
|
||||
}
|
||||
else if(delta < -GetScrollGestureDelta())
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetMouseWheelEvent(NO) position:pos]];
|
||||
_prev_long_press_position = pos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-(void)handleSingle2FingersTap:(UITapGestureRecognizer*)gesture
|
||||
{
|
||||
_toggle_mouse_button = !_toggle_mouse_button;
|
||||
}
|
||||
|
||||
-(void)handleSingle3FingersTap:(UITapGestureRecognizer*)gesture
|
||||
{
|
||||
[_session setToolbarVisible:![_session toolbarVisible]];
|
||||
[self showSessionToolbar:[_session toolbarVisible]];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Touch Pointer delegates
|
||||
// callback if touch pointer should be closed
|
||||
-(void)touchPointerClose
|
||||
{
|
||||
[self toggleTouchPointer:nil];
|
||||
}
|
||||
|
||||
// callback for a left click action
|
||||
-(void)touchPointerLeftClick:(CGPoint)pos down:(BOOL)down
|
||||
{
|
||||
CGPoint session_view_pos = [_touchpointer_view convertPoint:pos toView:_session_view];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetLeftMouseButtonClickEvent(down) position:session_view_pos]];
|
||||
}
|
||||
|
||||
// callback for a right click action
|
||||
-(void)touchPointerRightClick:(CGPoint)pos down:(BOOL)down
|
||||
{
|
||||
CGPoint session_view_pos = [_touchpointer_view convertPoint:pos toView:_session_view];
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetRightMouseButtonClickEvent(down) position:session_view_pos]];
|
||||
}
|
||||
|
||||
- (void)doAutoScrolling
|
||||
{
|
||||
int scrollX = 0;
|
||||
int scrollY = 0;
|
||||
CGPoint curPointerPos = [_touchpointer_view getPointerPosition];
|
||||
CGRect viewBounds = [_touchpointer_view bounds];
|
||||
CGRect scrollBounds = [_session_view bounds];
|
||||
|
||||
// add content insets to scroll bounds
|
||||
scrollBounds.size.width += [_session_scrollview contentInset].right;
|
||||
scrollBounds.size.height += [_session_scrollview contentInset].bottom;
|
||||
|
||||
// add zoom factor
|
||||
scrollBounds.size.width *= [_session_scrollview zoomScale];
|
||||
scrollBounds.size.height *= [_session_scrollview zoomScale];
|
||||
|
||||
if (curPointerPos.x > (viewBounds.size.width - [_touchpointer_view getPointerWidth]))
|
||||
scrollX = AUTOSCROLLDISTANCE;
|
||||
else if (curPointerPos.x < 0)
|
||||
scrollX = -AUTOSCROLLDISTANCE;
|
||||
|
||||
if (curPointerPos.y > (viewBounds.size.height - [_touchpointer_view getPointerHeight]))
|
||||
scrollY = AUTOSCROLLDISTANCE;
|
||||
else if (curPointerPos.y < (_session_toolbar_visible ? TOOLBAR_HEIGHT : 0))
|
||||
scrollY = -AUTOSCROLLDISTANCE;
|
||||
|
||||
CGPoint newOffset = [_session_scrollview contentOffset];
|
||||
newOffset.x += scrollX;
|
||||
newOffset.y += scrollY;
|
||||
|
||||
// if offset is going off screen - stop scrolling in that direction
|
||||
if (newOffset.x < 0)
|
||||
{
|
||||
scrollX = 0;
|
||||
newOffset.x = 0;
|
||||
}
|
||||
else if (newOffset.x > (scrollBounds.size.width - viewBounds.size.width))
|
||||
{
|
||||
scrollX = 0;
|
||||
newOffset.x = MAX(scrollBounds.size.width - viewBounds.size.width, 0);
|
||||
}
|
||||
if (newOffset.y < 0)
|
||||
{
|
||||
scrollY = 0;
|
||||
newOffset.y = 0;
|
||||
}
|
||||
else if (newOffset.y > (scrollBounds.size.height - viewBounds.size.height))
|
||||
{
|
||||
scrollY = 0;
|
||||
newOffset.y = MAX(scrollBounds.size.height - viewBounds.size.height, 0);
|
||||
}
|
||||
|
||||
// perform scrolling
|
||||
[_session_scrollview setContentOffset:newOffset];
|
||||
|
||||
// continue scrolling?
|
||||
if (scrollX != 0 || scrollY != 0)
|
||||
[self performSelector:@selector(doAutoScrolling) withObject:nil afterDelay:AUTOSCROLLTIMEOUT];
|
||||
else
|
||||
_is_autoscrolling = NO;
|
||||
}
|
||||
|
||||
// callback for a right click action
|
||||
-(void)touchPointerMove:(CGPoint)pos
|
||||
{
|
||||
CGPoint session_view_pos = [_touchpointer_view convertPoint:pos toView:_session_view];
|
||||
[self handleMouseMoveForPosition:session_view_pos];
|
||||
|
||||
if (_autoscroll_with_touchpointer && !_is_autoscrolling)
|
||||
{
|
||||
_is_autoscrolling = YES;
|
||||
[self performSelector:@selector(doAutoScrolling) withObject:nil afterDelay:AUTOSCROLLTIMEOUT];
|
||||
}
|
||||
}
|
||||
|
||||
// callback if scrolling is performed
|
||||
-(void)touchPointerScrollDown:(BOOL)down
|
||||
{
|
||||
[_session sendInputEvent:[self eventDescriptorForMouseEvent:GetMouseWheelEvent(down) position:CGPointZero]];
|
||||
}
|
||||
|
||||
// callback for toggling the standard keyboard
|
||||
-(void)touchPointerToggleKeyboard
|
||||
{
|
||||
if(_advanced_keyboard_visible)
|
||||
[self toggleKeyboardWhenOtherVisible:nil];
|
||||
else
|
||||
[self toggleKeyboard:nil];
|
||||
}
|
||||
|
||||
// callback for toggling the extended keyboard
|
||||
-(void)touchPointerToggleExtendedKeyboard
|
||||
{
|
||||
[self toggleExtKeyboard:nil];
|
||||
}
|
||||
|
||||
// callback for reset view
|
||||
-(void)touchPointerResetSessionView
|
||||
{
|
||||
[_session_scrollview setZoomScale:1.0 animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation RDPSessionViewController (Private)
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Helper functions
|
||||
|
||||
-(void)showSessionToolbar:(BOOL)show
|
||||
{
|
||||
// already shown or hidden?
|
||||
if (_session_toolbar_visible == show)
|
||||
return;
|
||||
|
||||
if(show)
|
||||
{
|
||||
[UIView beginAnimations:@"showToolbar" context:nil];
|
||||
[UIView setAnimationDuration:.4];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
|
||||
[_session_toolbar setFrame:CGRectMake(0.0, 0.0, [[self view] bounds].size.width, TOOLBAR_HEIGHT)];
|
||||
[UIView commitAnimations];
|
||||
_session_toolbar_visible = YES;
|
||||
}
|
||||
else
|
||||
{
|
||||
[UIView beginAnimations:@"hideToolbar" context:nil];
|
||||
[UIView setAnimationDuration:.4];
|
||||
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
|
||||
[_session_toolbar setFrame:CGRectMake(0.0, -TOOLBAR_HEIGHT, [[self view] bounds].size.width, TOOLBAR_HEIGHT)];
|
||||
[UIView commitAnimations];
|
||||
_session_toolbar_visible = NO;
|
||||
}
|
||||
}
|
||||
|
||||
-(UIToolbar*)keyboardToolbar
|
||||
{
|
||||
UIToolbar* keyboard_toolbar = [[[UIToolbar alloc] initWithFrame:CGRectNull] autorelease];
|
||||
[keyboard_toolbar setBarStyle:UIBarStyleBlackOpaque];
|
||||
|
||||
UIBarButtonItem* esc_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Esc" style:UIBarButtonItemStyleBordered target:self action:@selector(pressEscKey:)] autorelease];
|
||||
UIImage* win_icon = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"toolbar_icon_win" ofType:@"png"]];
|
||||
UIBarButtonItem* win_btn = [[[UIBarButtonItem alloc] initWithImage:win_icon style:UIBarButtonItemStyleBordered target:self action:@selector(toggleWinKey:)] autorelease];
|
||||
UIBarButtonItem* ctrl_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Ctrl" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleCtrlKey:)] autorelease];
|
||||
UIBarButtonItem* alt_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Alt" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleAltKey:)] autorelease];
|
||||
UIBarButtonItem* ext_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Ext" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleKeyboardWhenOtherVisible:)] autorelease];
|
||||
UIBarButtonItem* done_btn = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(toggleKeyboard:)] autorelease];
|
||||
UIBarButtonItem* flex_spacer = [[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil] autorelease];
|
||||
|
||||
// iPad gets a shift button, iphone doesn't (there's just not enough space ...)
|
||||
NSArray* items;
|
||||
if(IsPad())
|
||||
{
|
||||
UIBarButtonItem* shift_btn = [[[UIBarButtonItem alloc] initWithTitle:@"Shift" style:UIBarButtonItemStyleBordered target:self action:@selector(toggleShiftKey:)] autorelease];
|
||||
items = [NSArray arrayWithObjects:esc_btn, flex_spacer,
|
||||
shift_btn, flex_spacer,
|
||||
ctrl_btn, flex_spacer,
|
||||
win_btn, flex_spacer,
|
||||
alt_btn, flex_spacer,
|
||||
ext_btn, flex_spacer, done_btn, nil];
|
||||
}
|
||||
else
|
||||
{
|
||||
items = [NSArray arrayWithObjects:esc_btn, flex_spacer, ctrl_btn, flex_spacer, win_btn, flex_spacer, alt_btn, flex_spacer, ext_btn, flex_spacer, done_btn, nil];
|
||||
}
|
||||
|
||||
[keyboard_toolbar setItems:items];
|
||||
[keyboard_toolbar sizeToFit];
|
||||
return keyboard_toolbar;
|
||||
}
|
||||
|
||||
- (void)initGestureRecognizers
|
||||
{
|
||||
// single and double tap recognizer
|
||||
UITapGestureRecognizer* doubleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)] autorelease];
|
||||
[doubleTapRecognizer setNumberOfTouchesRequired:1];
|
||||
[doubleTapRecognizer setNumberOfTapsRequired:2];
|
||||
|
||||
UITapGestureRecognizer* singleTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)] autorelease];
|
||||
[singleTapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
|
||||
[singleTapRecognizer setNumberOfTouchesRequired:1];
|
||||
[singleTapRecognizer setNumberOfTapsRequired:1];
|
||||
|
||||
// 2 fingers - tap recognizer
|
||||
UITapGestureRecognizer* single2FingersTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingle2FingersTap:)] autorelease];
|
||||
[single2FingersTapRecognizer setNumberOfTouchesRequired:2];
|
||||
[single2FingersTapRecognizer setNumberOfTapsRequired:1];
|
||||
|
||||
// long press gesture recognizer
|
||||
UILongPressGestureRecognizer* longPressRecognizer = [[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)] autorelease];
|
||||
[longPressRecognizer setMinimumPressDuration:0.5];
|
||||
|
||||
// double long press gesture recognizer
|
||||
UILongPressGestureRecognizer* doubleLongPressRecognizer = [[[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleLongPress:)] autorelease];
|
||||
[doubleLongPressRecognizer setNumberOfTouchesRequired:2];
|
||||
[doubleLongPressRecognizer setMinimumPressDuration:0.5];
|
||||
|
||||
// 3 finger, single tap gesture for showing/hiding the toolbar
|
||||
UITapGestureRecognizer* single3FingersTapRecognizer = [[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingle3FingersTap:)] autorelease];
|
||||
[single3FingersTapRecognizer setNumberOfTapsRequired:1];
|
||||
[single3FingersTapRecognizer setNumberOfTouchesRequired:3];
|
||||
|
||||
// add gestures to scroll view
|
||||
[_session_scrollview addGestureRecognizer:singleTapRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:doubleTapRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:single2FingersTapRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:longPressRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:doubleLongPressRecognizer];
|
||||
[_session_scrollview addGestureRecognizer:single3FingersTapRecognizer];
|
||||
}
|
||||
|
||||
- (void)suspendSession
|
||||
{
|
||||
// suspend session and pop navigation controller
|
||||
[_session suspend];
|
||||
|
||||
// pop current view controller
|
||||
[[self navigationController] popViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (NSDictionary*)eventDescriptorForMouseEvent:(int)event position:(CGPoint)position
|
||||
{
|
||||
return [NSDictionary dictionaryWithObjectsAndKeys:
|
||||
@"mouse", @"type",
|
||||
[NSNumber numberWithUnsignedShort:event], @"flags",
|
||||
[NSNumber numberWithUnsignedShort:lrintf(position.x)], @"coord_x",
|
||||
[NSNumber numberWithUnsignedShort:lrintf(position.y)], @"coord_y",
|
||||
nil];
|
||||
}
|
||||
|
||||
- (void)sendDelayedMouseEventWithTimer:(NSTimer*)timer
|
||||
{
|
||||
_mouse_move_event_timer = nil;
|
||||
NSDictionary* event = [timer userInfo];
|
||||
[_session sendInputEvent:event];
|
||||
[timer autorelease];
|
||||
}
|
||||
|
||||
- (void)handleMouseMoveForPosition:(CGPoint)position
|
||||
{
|
||||
NSDictionary* event = [self eventDescriptorForMouseEvent:PTR_FLAGS_MOVE position:position];
|
||||
|
||||
// cancel pending mouse move events
|
||||
[_mouse_move_event_timer invalidate];
|
||||
_mouse_move_events_skipped++;
|
||||
|
||||
if (_mouse_move_events_skipped >= 5)
|
||||
{
|
||||
[_session sendInputEvent:event];
|
||||
_mouse_move_events_skipped = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
[_mouse_move_event_timer autorelease];
|
||||
_mouse_move_event_timer = [[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(sendDelayedMouseEventWithTimer:) userInfo:event repeats:NO] retain];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
33
client/iOS/Controllers/ScreenSelectionController.h
Normal file
33
client/iOS/Controllers/ScreenSelectionController.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
controller for screen settings selection
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "EditorBaseController.h"
|
||||
|
||||
@class ConnectionParams;
|
||||
@class OrderedDictionary;
|
||||
|
||||
@interface ScreenSelectionController : EditorBaseController
|
||||
{
|
||||
@private
|
||||
NSString* _keyPath;
|
||||
ConnectionParams* _params;
|
||||
|
||||
// avaiable options
|
||||
OrderedDictionary* _color_options;
|
||||
NSArray* _resolution_modes;
|
||||
|
||||
// current selections
|
||||
int _selection_color;
|
||||
int _selection_resolution;
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params;
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:(NSString*)keyPath;
|
||||
|
||||
@end
|
||||
234
client/iOS/Controllers/ScreenSelectionController.m
Normal file
234
client/iOS/Controllers/ScreenSelectionController.m
Normal file
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
controller for screen settings selection
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "ScreenSelectionController.h"
|
||||
#import "Utils.h"
|
||||
#import "OrderedDictionary.h"
|
||||
#import "ConnectionParams.h"
|
||||
|
||||
@interface ScreenSelectionController (Private)
|
||||
-(NSString*)keyPathForKey:(NSString*)key;
|
||||
@end
|
||||
|
||||
@implementation ScreenSelectionController
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params
|
||||
{
|
||||
return [self initWithConnectionParams:params keyPath:nil];
|
||||
}
|
||||
|
||||
- (id)initWithConnectionParams:(ConnectionParams*)params keyPath:(NSString*)keyPath
|
||||
{
|
||||
self = [super initWithStyle:UITableViewStyleGrouped];
|
||||
if (self)
|
||||
{
|
||||
_params = [params retain];
|
||||
_keyPath = (keyPath != nil ? [keyPath retain] : nil);
|
||||
|
||||
_color_options = (OrderedDictionary*)[SelectionForColorSetting() retain];
|
||||
_resolution_modes = [ResolutionModes() retain];
|
||||
|
||||
// init current selections
|
||||
NSUInteger idx = [_color_options indexForValue:[NSNumber numberWithInt:[_params intForKeyPath:[self keyPathForKey:@"colors"]]]];
|
||||
_selection_color = (idx != NSNotFound) ? idx : 0;
|
||||
|
||||
idx = [_resolution_modes indexOfObject:ScreenResolutionDescription([_params intForKeyPath:[self keyPathForKey:@"screen_resolution_type"]],
|
||||
[_params intForKeyPath:[self keyPathForKey:@"width"]],
|
||||
[_params intForKeyPath:[self keyPathForKey:@"height"]])];
|
||||
_selection_resolution = (idx != NSNotFound) ? idx : 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[super dealloc];
|
||||
[_params autorelease];
|
||||
[_keyPath autorelease];
|
||||
[_color_options autorelease];
|
||||
[_resolution_modes autorelease];
|
||||
}
|
||||
|
||||
-(NSString*)keyPathForKey:(NSString*)key
|
||||
{
|
||||
if (_keyPath)
|
||||
return [_keyPath stringByAppendingFormat:@".%@", key];
|
||||
return key;
|
||||
}
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
// Return YES for supported orientations
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
// Return the number of rows in the section.
|
||||
if (section == 0)
|
||||
return [_color_options count];
|
||||
return [_resolution_modes count] + 2; // +2 for custom width/height input fields
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
UITableViewCell *cell = nil;
|
||||
switch ([indexPath section])
|
||||
{
|
||||
case 0:
|
||||
cell = [self tableViewCellFromIdentifier:TableCellIdentifierMultiChoice];
|
||||
[[cell textLabel] setText:[_color_options keyAtIndex:[indexPath row]]];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if ([indexPath row] < [_resolution_modes count])
|
||||
{
|
||||
cell = [self tableViewCellFromIdentifier:TableCellIdentifierMultiChoice];
|
||||
[[cell textLabel] setText:[_resolution_modes objectAtIndex:[indexPath row]]];
|
||||
}
|
||||
else
|
||||
cell = [self tableViewCellFromIdentifier:TableCellIdentifierText];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ([indexPath section] == 1)
|
||||
{
|
||||
BOOL enabled = ([_params intForKeyPath:[self keyPathForKey:@"screen_resolution_type"]] == TSXScreenOptionCustom);
|
||||
if ([indexPath row] == [_resolution_modes count])
|
||||
{
|
||||
int value = [_params intForKeyPath:[self keyPathForKey:@"width"]];
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell label] setText:NSLocalizedString(@"Width", @"Custom Screen Width")];
|
||||
[[textCell textfield] setText:[NSString stringWithFormat:@"%d", value ? value : 800]];
|
||||
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
|
||||
[[textCell label] setEnabled:enabled];
|
||||
[[textCell textfield] setEnabled:enabled];
|
||||
[[textCell textfield] setTag:1];
|
||||
}
|
||||
else if ([indexPath row] == ([_resolution_modes count] + 1))
|
||||
{
|
||||
int value = [_params intForKeyPath:[self keyPathForKey:@"height"]];
|
||||
EditTextTableViewCell* textCell = (EditTextTableViewCell*)cell;
|
||||
[[textCell label] setText:NSLocalizedString(@"Height", @"Custom Screen Height")];
|
||||
[[textCell textfield] setText:[NSString stringWithFormat:@"%d", value ? value : 600]];
|
||||
[[textCell textfield] setKeyboardType:UIKeyboardTypeNumberPad];
|
||||
[[textCell label] setEnabled:enabled];
|
||||
[[textCell textfield] setEnabled:enabled];
|
||||
[[textCell textfield] setTag:2];
|
||||
}
|
||||
}
|
||||
|
||||
// set default checkmark
|
||||
if([indexPath row] == ([indexPath section] == 0 ? _selection_color : _selection_resolution))
|
||||
[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
|
||||
else
|
||||
[cell setAccessoryType:UITableViewCellAccessoryNone];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
#pragma mark - Table view delegate
|
||||
|
||||
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
// custom widht/height cells are not selectable
|
||||
if ([indexPath section] == 1 && [indexPath row] >= [_resolution_modes count])
|
||||
return;
|
||||
|
||||
// has selection change?
|
||||
int cur_selection = ([indexPath section] == 0 ? _selection_color : _selection_resolution);
|
||||
if([indexPath row] != cur_selection)
|
||||
{
|
||||
[tableView deselectRowAtIndexPath:indexPath animated:NO];
|
||||
|
||||
NSIndexPath* oldIndexPath = [NSIndexPath indexPathForRow:cur_selection inSection:[indexPath section]];
|
||||
|
||||
// clear old checkmark
|
||||
UITableViewCell* old_sel_cell = [tableView cellForRowAtIndexPath:oldIndexPath];
|
||||
old_sel_cell.accessoryType = UITableViewCellAccessoryNone;
|
||||
|
||||
// set new checkmark
|
||||
UITableViewCell* new_sel_cell = [tableView cellForRowAtIndexPath:indexPath];
|
||||
new_sel_cell.accessoryType = UITableViewCellAccessoryCheckmark;
|
||||
|
||||
if ([indexPath section] == 0)
|
||||
{
|
||||
// get value from color dictionary
|
||||
int sel_value = [[_color_options valueForKey:[_color_options keyAtIndex:[indexPath row]]] intValue];
|
||||
|
||||
// update selection index and params value
|
||||
[_params setInt:sel_value forKeyPath:[self keyPathForKey:@"colors"]];
|
||||
_selection_color = [indexPath row];
|
||||
}
|
||||
else
|
||||
{
|
||||
// update selection index and params value
|
||||
int width, height;
|
||||
TSXScreenOptions mode;
|
||||
ScanScreenResolution([_resolution_modes objectAtIndex:[indexPath row]], &width, &height, &mode);
|
||||
[_params setInt:mode forKeyPath:[self keyPathForKey:@"screen_resolution_type"]];
|
||||
if (mode != TSXScreenOptionCustom)
|
||||
{
|
||||
[_params setInt:width forKeyPath:[self keyPathForKey:@"width"]];
|
||||
[_params setInt:height forKeyPath:[self keyPathForKey:@"height"]];
|
||||
}
|
||||
_selection_resolution = [indexPath row];
|
||||
|
||||
// refresh width/height edit fields if custom selection changed
|
||||
NSArray* indexPaths = [NSArray arrayWithObjects:[NSIndexPath indexPathForRow:[_resolution_modes count] inSection:1],
|
||||
[NSIndexPath indexPathForRow:([_resolution_modes count] + 1) inSection:1], nil];
|
||||
[[self tableView] reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Text Field delegate
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField*)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
|
||||
{
|
||||
|
||||
switch([textField tag])
|
||||
{
|
||||
// update resolution settings (and check for invalid input)
|
||||
case 1:
|
||||
if ([[textField text] intValue] < 640) [textField setText:@"640"];
|
||||
[_params setInt:[[textField text] intValue] forKeyPath:[self keyPathForKey:@"width"]];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if ([[textField text] intValue] < 480) [textField setText:@"480"];
|
||||
[_params setInt:[[textField text] intValue] forKeyPath:[self keyPathForKey:@"height"]];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
29
client/iOS/Controllers/VerifyCertificateController.h
Normal file
29
client/iOS/Controllers/VerifyCertificateController.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
Certificate verification controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class RDPSession;
|
||||
|
||||
@interface VerifyCertificateController : UIViewController
|
||||
{
|
||||
@private
|
||||
IBOutlet UILabel* _label_issuer;
|
||||
IBOutlet UIButton* _btn_accept;
|
||||
IBOutlet UIButton* _btn_decline;
|
||||
IBOutlet UILabel* _label_message;
|
||||
IBOutlet UILabel* _label_for_issuer;
|
||||
|
||||
RDPSession* _session;
|
||||
NSMutableDictionary* _params;
|
||||
}
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession*)session params:(NSMutableDictionary*)params;
|
||||
|
||||
@end
|
||||
79
client/iOS/Controllers/VerifyCertificateController.m
Normal file
79
client/iOS/Controllers/VerifyCertificateController.m
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
Certificate verification controller
|
||||
|
||||
Copyright 2013 Thinstuff Technologies GmbH, Author: Martin Fleisz
|
||||
|
||||
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/.
|
||||
*/
|
||||
|
||||
#import "VerifyCertificateController.h"
|
||||
#import "RDPSession.h"
|
||||
|
||||
@implementation VerifyCertificateController
|
||||
|
||||
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil session:(RDPSession *)session params:(NSMutableDictionary *)params
|
||||
{
|
||||
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
|
||||
if (self) {
|
||||
_session = session;
|
||||
_params = params;
|
||||
[self setModalPresentationStyle:UIModalPresentationFormSheet];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
NSString* message = NSLocalizedString(@"The identity of the remote computer cannot be verified. Do you want to connect anyway?", @"Verify certificate view message");
|
||||
|
||||
// init strings
|
||||
[_label_message setText:message];
|
||||
[_label_for_issuer setText:NSLocalizedString(@"Issuer:", @"Verify certificate view issuer label")];
|
||||
[_btn_accept setTitle:NSLocalizedString(@"Yes", @"Yes Button") forState:UIControlStateNormal];
|
||||
[_btn_decline setTitle:NSLocalizedString(@"No", @"No Button") forState:UIControlStateNormal];
|
||||
|
||||
[_label_issuer setText:[_params valueForKey:@"issuer"]];
|
||||
}
|
||||
|
||||
- (void)viewDidUnload
|
||||
{
|
||||
[super viewDidUnload];
|
||||
// Release any retained subviews of the main view.
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
|
||||
// set signal
|
||||
[[_session uiRequestCompleted] signal];
|
||||
}
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Action handlers
|
||||
|
||||
- (IBAction)acceptPressed:(id)sender
|
||||
{
|
||||
[_params setValue:[NSNumber numberWithBool:YES] forKey:@"result"];
|
||||
|
||||
// dismiss controller
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (IBAction)declinePressed:(id)sender
|
||||
{
|
||||
[_params setValue:[NSNumber numberWithBool:NO] forKey:@"result"];
|
||||
|
||||
// dismiss controller
|
||||
[self dismissModalViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user