Blob Blame History Raw
/*
 Bookmark editor controller

 Copyright 2013 Thincast 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"
#import "BlockAlertView.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
		if ([[bookmark uuid] length] == 0)
			_bookmark = [bookmark copy];
		else
			_bookmark = [bookmark copyWithUUID];
		_params = [_bookmark params];

		_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 -
#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 label] length] == 0 || [[_params StringForKey:@"hostname"] length] == 0 ||
	    [_params intForKey:@"port"] == 0)
	{
		BlockAlertView *alertView = [BlockAlertView
		    alertWithTitle: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")];
		[alertView
		    setCancelButtonWithTitle:NSLocalizedString(@"Cancel", @"Cancel Button")
		                       block:^{
			                       // cancel bookmark editing and return to previous view controller
			                       [[self navigationController] popViewControllerAnimated:YES];
		                       }];
		[alertView addButtonWithTitle:NSLocalizedString(@"Continue", @"Continue Button") block:nil];
		[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