FreeRDP/client/iOS/Controllers/BookmarkListController.m
2013-12-04 12:30:33 +01:00

835 lines
31 KiB
Objective-C

/*
bookmarks and active session view 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 "BookmarkListController.h"
#import "Utils.h"
#import "BookmarkEditorController.h"
#import "RDPSessionViewController.h"
#import "Toast+UIView.h"
#import "Reachability.h"
#import "GlobalDefaults.h"
#import "BlockAlertView.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] autorelease]];
// 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]];
}
- (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
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_temporary_bookmark release];
[_connection_history release];
[_active_sessions release];
[_manual_search_result release];
[_manual_bookmarks release];
[_star_on_img release];
[_star_off_img 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"]];
[[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)
{
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] autorelease];
[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
ComputerBookmark *bookmark = [[[ComputerBookmark alloc] initWithBaseDefaultParameters] autorelease];
BookmarkEditorController* bookmarkEditorController = [[[BookmarkEditorController alloc] initWithBookmark:bookmark] 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] autorelease];
[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
[_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 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 (![_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");
BlockAlertView* alert = [BlockAlertView alertWithTitle:title message:message];
[alert setCancelButtonWithTitle:NSLocalizedString(@"No", @"No Button") block:nil];
[alert addButtonWithTitle:NSLocalizedString(@"Yes", @"Yes Button") block:^{
if (_temporary_bookmark)
{
[_manual_bookmarks addObject:_temporary_bookmark];
[_tableView reloadSections:[NSIndexSet indexSetWithIndex:SECTION_BOOKMARKS] withRowAnimation:UITableViewRowAnimationNone];
[_temporary_bookmark autorelease];
_temporary_bookmark = 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 - 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 otherwise replace it
BOOL found = NO;
for (int idx = 0; idx < [_manual_bookmarks count]; ++idx)
{
if ([[bookmark uuid] isEqualToString:[[_manual_bookmarks objectAtIndex:idx] uuid]])
{
[_manual_bookmarks replaceObjectAtIndex:idx withObject:bookmark];
found = YES;
break;
}
}
if (!found)
[_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);
}
- (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];
if([searchText length] > 0)
{
_manual_search_result = [FilterBookmarks(_manual_bookmarks, [searchText componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]) retain];
_history_search_result = [FilterHistory(_connection_history, searchText) retain];
}
else
{
_history_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];
[_manual_bookmarks addObject:[[[GlobalDefaults sharedGlobalDefaults] newTestServerBookmark] autorelease]];
}
}
- (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.freerdp.ifreerdp.bookmarks.plist"]];
}
- (NSURL*)connectionHistoryDataStoreURL
{
return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], @"com.freerdp.ifreerdp.connection_history.plist"]];
}
@end