//
// ServerDetailViewController.m
// p4scout
//
// Created by Work on 10/18/08.
// Copyright 2008 Perforce Software, Inc. All rights reserved.
//
#import "ServerDetailViewController.h"
#import "ServerTableController.h"
#import "P4Server.h"
#import "P4ConnectionEditor.h"
#import "MonitorTableViewController.h"
#import "NSStringAdditions.h"
#import "UIToolbarAdditions.h"
static const int ActivityButtonBarItemPosition = 2;
@interface ServerDetailViewController ()
-(void)setActive:(BOOL)active;
-(ServerTableController*)serverTableController;
-(void)configureEditButton;
-(IBAction)addToSavedList:(id)sender;
-(NSURL*)sshUrl;
@end
@implementation ServerDetailViewController
@synthesize server;
// Override initWithNibName:bundle: to load the view using a nib file then perform additional customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (!(self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]))
return self;
return self;
}
/*
// Implement loadView to create a view hierarchy programmatically.
- (void)loadView {
[super loadView];
}
*/
-(NSURL*)sshUrl
{
NSString * user = [server user];
if (!user)
user = [P4Server defaultUser];
NSString * urlStr = [NSString stringWithFormat:@"ssh://%@@%@", user, server.remoteHostname];
NSURL * url = [NSURL URLWithString:urlStr];
return url;
}
-(NSTimeInterval)timeIntervalFromString:(NSString *)s
{
NSArray * times = [s componentsSeparatedByString:@":"];
if ( [times count] != 3 )
return -1;
NSTimeInterval uptime = 0;
uptime += [[times objectAtIndex:0] intValue] * 60 * 60;
uptime += [[times objectAtIndex:1] intValue] * 60;
uptime += [[times objectAtIndex:2] intValue];
return uptime;
}
-(NSTimeInterval)uptime
{
return [self timeIntervalFromString:[[self.server info] objectForKey:@"serverUptime"]];
}
-(NSString *)uptimeUnitString
{
NSTimeInterval uptime = [self uptime];
if ( uptime > (60*60*24) )
return @"days";
if ( uptime > (60*60) )
return @"hours";
if ( uptime > 60 )
return @"minutes";
if ( uptime < 0 )
return @"hours";
return @"seconds";
}
-(NSString *)uptimeString
{
NSTimeInterval uptime = [self uptime];
if ( uptime < 0 )
return @"?";
if ( uptime > (60*60*24) )
return [[NSNumber numberWithInt: uptime / (60*60*24)] stringValue];
if ( uptime > (60*60) )
return [[NSNumber numberWithInt: uptime / (60*60)] stringValue];
if ( uptime > 60 )
return [[NSNumber numberWithInt: uptime / 60] stringValue];
return [[NSNumber numberWithInt: uptime] stringValue];
}
-(void)updateUserDataForServer:(P4Server *)s
{
userCount.text = [NSString stringWithFormat:@"%d", s.numberOfUsers];
maxUserCount.text = [NSString stringWithFormat:@"%d", s.maximumUserCount];
int remainingUsers = 0;
float progress = 0;
if ( s.maximumUserCount )
{
remainingUsers = s.maximumUserCount - s.numberOfUsers;
progress = (float)s.numberOfUsers / (float)s.maximumUserCount;
}
userCountProgressView.progress = progress;
// show users warning
if ( progress > 0.95 && remainingUsers < 5 )
{
userCount.textColor = [UIColor redColor];
usersAlertLabel.hidden = NO;
}
else
{
userCount.textColor = [UIColor darkTextColor];
usersAlertLabel.hidden = YES;
}
}
-(void)displayDataForServer:(P4Server *)s
{
serverNameLabel.text = s.label;
if ( !serverNameLabel.text )
serverNameLabel.text = s.p4port;
if ( !serverNameLabel.text )
serverNameLabel.text = @"perforce:1666";
NSDictionary * info = s.info;
serverAddressLabel.text = [info objectForKey:@"serverAddress"];
uptimeLabel.text = [self uptimeString];
uptimeUnitLabel.text = [self uptimeUnitString];
currentCommandLabel.text = s.currentCommandDescription;
if ( s.connectionState == Online || s.connectionState == Connecting )
{
[serverErrorMessage setHidden:YES];
connectionStatusIcon.hidden = YES;
[infoView setHidden:NO];
}
else
{
[infoView setHidden:YES];
[serverErrorMessage setHidden:NO];
serverAddressLabel.text = s.p4port;
connectionStatusIcon.hidden = NO;
if ( !s.reachable )
{
connectionStatusIcon.image = [UIImage imageNamed:@"StatusUnreachable.png"];
serverErrorMessage.text = [NSString stringWithFormat:@"Cannot reach %@ on this network", s.remoteHostname];
}
else if ( s.connectionState == Offline )
{
connectionStatusIcon.image = [UIImage imageNamed:@"StatusOffline.png"];
serverErrorMessage.text = @"Cannot connect to the Perforce Server";
}
}
versionLabel.text = s.simpleVersion;
platformLabel.text = s.platform;
int taskCount = [s.monitorInfo count];
if ( !s.monitorEnabled )
{
monitorTextView.text = @"Monitor not enabled";
}
else if ( s.requiresTicket )
{
monitorTextView.text = @"Process information not available for security level 3 servers";
}
else if ( !s.monitorInfo )
{
monitorTextView.text = @"Not loaded";
}
else
{
if ( s.currentUserExistsOnServer )
{
monitorTextView.text = [NSString stringWithFormat:@"%@ processes over %d minutes",
taskCount ? [NSString stringWithFormat:@"%d", taskCount] : @"No",
(int)(MonitorTaskTimeThreshold / 60)];
}
else
{
monitorTextView.text = [NSString stringWithFormat:@"Skipped to avoid creating a new user (%@)", s.user ? s.user : [P4Server defaultUser] ];
}
}
monitorAlertLabel.hidden = (taskCount <= 0);
monitorTableButton.hidden = (taskCount <= 0);
NSTimeInterval timeLeft = s.remainingLicenseTime;
if ( s.hasLicense && timeLeft < (60*60*24*7) ) // warns << 14 days
{
licenseLabel.textColor = [UIColor redColor];
licenseAlertLabel.hidden = NO;
}
else
{
licenseLabel.textColor = [UIColor darkTextColor];
licenseAlertLabel.hidden = YES;
}
if ( !s.hasLicense )
{
licenseLabel.text = @"none";
}
else if ( timeLeft <= 0 )
{
licenseLabel.text = @"EXPIRED";
}
else
{
licenseLabel.text = [NSString stringWithFormat:@"%@ left", [NSString coarseStringWithTimeInterval:timeLeft]];
}
[self updateUserDataForServer:s];
if ( s.lastError )
{
[errorTextView setText:s.lastError.localizedDescription];
errorTextView.hidden = NO;
errorAlertLabel.hidden = NO;
}
else
{
errorTextView.hidden = YES;
errorAlertLabel.hidden = YES;
}
// Only turn it on, never off, because an animation might be
// turning it off slowly. If we turn it off, it will just blink it off,
// interrupting the animation
if ( s.discovered )
discoveredBadgeLabel.hidden = false;
}
-(void)observeValueForKeyPath:(NSString *)key
ofObject:(id)object
change:(NSDictionary *)dict
context:(void *)context
{
if ( ![key isEqualToString:InfoPropertyKey] &&
![key isEqualToString:MonitorInfoPropertyKey] &&
![key isEqualToString:NumberOfUsersPropertyKey] &&
![key isEqualToString:ConnectionStatePropertyKey] &&
![key isEqualToString:ActivePropertyKey] &&
![key isEqualToString:CurrentCommandPropertyKey] )
return;
if ([key isEqualToString:ActivePropertyKey])
{
P4Server * s = (P4Server*)object;
[self setActive:s.active];
return;
}
if ([key isEqualToString:NumberOfUsersPropertyKey])
{
[self updateUserDataForServer:object];
return;
}
[self displayDataForServer:object];
}
-(void)setActive:(BOOL)active
{
if ( active )
{
if ( [toolbar.items objectAtIndex:ActivityButtonBarItemPosition] != activityIndicatorViewItem )
[toolbar insertItem:activityIndicatorViewItem inItemsAtIndex:ActivityButtonBarItemPosition animated:NO];
[activityIndicatorView startAnimating];
currentCommandLabel.textAlignment = UITextAlignmentLeft;
}
else
{
[activityIndicatorView stopAnimating];
if ( [toolbar.items objectAtIndex:ActivityButtonBarItemPosition] == activityIndicatorViewItem )
[toolbar removeItemFromItemsAtIndex:ActivityButtonBarItemPosition animated:NO];
currentCommandLabel.textAlignment = UITextAlignmentCenter;
}
currentCommandLabel.text = server.currentCommandDescription;
}
-(void)observeServer:(P4Server*)s
{
[s addObserver:self forKeyPath:InfoPropertyKey options:NSKeyValueObservingOptionNew context:NULL];
[s addObserver:self forKeyPath:MonitorInfoPropertyKey options:NSKeyValueObservingOptionNew context:NULL];
[s addObserver:self forKeyPath:NumberOfUsersPropertyKey options:NSKeyValueObservingOptionNew context:NULL];
[s addObserver:self forKeyPath:ConnectionStatePropertyKey options:NSKeyValueObservingOptionNew context:NULL];
[s addObserver:self forKeyPath:ActivePropertyKey options:NSKeyValueObservingOptionNew context:NULL];
[s addObserver:self forKeyPath:CurrentCommandPropertyKey options:NSKeyValueObservingOptionNew context:NULL];
}
-(void)unobserveServer:(P4Server*)s
{
[s removeObserver:self forKeyPath:InfoPropertyKey];
[s removeObserver:self forKeyPath:MonitorInfoPropertyKey];
[s removeObserver:self forKeyPath:NumberOfUsersPropertyKey];
[s removeObserver:self forKeyPath:ConnectionStatePropertyKey];
[s removeObserver:self forKeyPath:ActivePropertyKey];
[s removeObserver:self forKeyPath:CurrentCommandPropertyKey];
}
-(void)setServer:(P4Server *)s
{
BOOL wasActive = server.active;
if ( server == s )
return;
[self unobserveServer:server];
[s retain];
[server release];
server = s;
[self observeServer:server];
monitorTableViewController.server = s;
if ( wasActive != server.active )
[self setActive:server.active];
[self displayDataForServer:server];
[self configureEditButton];
}
-(void)configureEditButton
{
if ( self.server.discovered )
{
[editBarButtonItem setAction:@selector(addToSavedList:)];
editBarButtonItem.title = @"Keep";
}
else
{
[editBarButtonItem setAction:@selector(edit:)];
editBarButtonItem.title = @"Edit";
}
}
-(IBAction)refresh:(id)sender
{
[server refresh:self];
}
-(IBAction)addToSavedList:(id)sender
{
NSAssert( self.server.discovered, @"server not discoverable" );
// Make a copy of the discovered server, add it to the master list,
// and reset ourselves to use it
// We use the "serverAddress" field as the saved address rather than p4port
// because p4port likely refers to items that can only be seen when
// on the local network. We'd like to be able to connect even when
// outside the local network
P4Server * s = [[[P4Server alloc] init] autorelease];
s.p4port = [self.server.info objectForKey:@"serverAddress"];
s.label = self.server.label;
[s refresh:self];
[[self serverTableController] addServer:s];
self.server = s;
[UIView beginAnimations:@"frame" context:nil];
[UIView setAnimationDuration:1.0];
CGRect disappearingFrame = discoveredBadgeLabel.frame;
disappearingFrame.origin.y -= disappearingFrame.size.height;
discoveredBadgeLabel.frame = disappearingFrame;
[UIView commitAnimations];
}
-(IBAction)edit:(id)sender
{
editViewController.deleteButton = deleteButton;
editViewController.server = self.server; // we need to specify a copy
[self.navigationController presentModalViewController:serverEditDialogController animated:YES];
}
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(int)index
{
if ( index != 0 ) // delete button
return;
[self.navigationController dismissModalViewControllerAnimated:YES]; // set ourself to the copy
[[self serverTableController] removeServer:self.server];
[self.navigationController popViewControllerAnimated:YES]; // pop ourselves off the stack
}
-(ServerTableController*)serverTableController
{
return (ServerTableController*)[self.navigationController.viewControllers objectAtIndex:0];
}
-(IBAction)remove:(id)sender
{
// open a dialog with an OK and cancel button
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:@"Delete Server?"
delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:@"Delete server" otherButtonTitles:nil];
actionSheet.actionSheetStyle = UIActionSheetStyleDefault;
[actionSheet showInView:self.view]; // show from our table view (pops up in the middle of the table)
[actionSheet release];
}
- (IBAction)save:(id)sender
{
[self.navigationController dismissModalViewControllerAnimated:YES]; // set ourself to the copy
[server refresh:self];
[self displayDataForServer:server];
}
- (IBAction)cancel:(id)sender
{
[self.navigationController dismissModalViewControllerAnimated:YES]; // we should not set ourself to the copy
}
-(IBAction)openSSH:(id)sender
{
[[UIApplication sharedApplication] openURL:[self sshUrl]];
}
-(IBAction)showTasks:(id)sender
{
if ( [server.monitorInfo count] <= 0 )
return;
[self.navigationController pushViewController:monitorTableViewController animated:YES];
}
// Implement viewDidLoad to do additional setup after loading the view.
- (void)viewDidLoad {
self.navigationItem.title = @"Detail";
self.navigationItem.rightBarButtonItem = editButton;
monitorTableViewController.server = self.server;
[self displayDataForServer:server];
[self setActive:server.active];
[self configureEditButton];
if (![[UIApplication sharedApplication] canOpenURL:[self sshUrl]])
[toolbar removeItem:sshButton fromItemsAnimated:NO];
[super viewDidLoad];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview
// Release anything that's not essential, such as cached data
}
- (void)dealloc {
[self unobserveServer:server];
[server release];
[super dealloc];
}
@end
# |
Change |
User |
Description |
Committed |
|
#1
|
8980 |
Matt Attaway |
Add source code for both the Android and iOS versions of P4Scout. |
|
|