Logo Search packages:      
Sourcecode: adun.app version File versions  Download package

ViewController.m

/* 
   Project: UL

   Copyright (C) 2005 Michael Johnston & Jordi Villa-Freixa

   Author: Michael Johnston

   Created: 2005-05-23 13:29:49 +0200 by michael johnston
   
   Application Controller

   This application is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.
 
   This application is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.
 
   You should have received a copy of the GNU General Public
   License along with this library; if not, write to the Free
   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
*/

#include "ViewController.h"

@implementation ViewController

- (void) _makeSplashScreen
{
      NSRect mainScreenFrame;
      NSPoint mainScreenCenter;
      NSSize splashContentSize;
      NSRect splashWindowContentRect;
      NSImage* splashImage;

      splashImage = [[NSImage alloc] initWithContentsOfFile: 
                  [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent: @"splash.tiff"]];
      splashContentSize = [splashImage size];
      
      mainScreenFrame = [statusWindow frame];
      mainScreenCenter = NSMakePoint(mainScreenFrame.origin.x + mainScreenFrame.size.width/2, 
                              mainScreenFrame.origin.y + mainScreenFrame.size.height/2);
      
      splashWindowContentRect.size = splashContentSize;
      splashWindowContentRect.origin.x = mainScreenCenter.x - splashContentSize.width/2;
      splashWindowContentRect.origin.y = mainScreenCenter.y - splashContentSize.height/2;

      splashScreen = [[NSWindow alloc] initWithContentRect: splashWindowContentRect
                        styleMask: NSBorderlessWindowMask
                        backing: NSBackingStoreRetained
                        defer: NO];

      splashScreenImageView = [[NSImageView alloc] init];
      [splashScreenImageView setImage: splashImage];
      [(NSWindow*)splashScreen setContentView: splashScreenImageView];
      [splashScreen setLevel: NSFloatingWindowLevel];
      [splashScreen setOpaque: NO];

      [splashScreen makeKeyAndOrderFront: self];
}

+ (void)initialize
{
      NSMutableDictionary *defaults = [NSMutableDictionary dictionary];
      id debugLevels;

      [defaults setObject: NSHomeDirectory()  forKey:@"PDBDirectory"];
      [defaults setObject: [NSHomeDirectory() stringByAppendingPathComponent: @"adun/buildOutput"]
            forKey: @"BuildOutput"];
      [defaults setObject: [NSHomeDirectory() stringByAppendingPathComponent: @"adun/UL.log"]
            forKey: @"LogFile"];
      [defaults setObject: [NSNumber numberWithDouble: 300] forKey: @"AutosaveInterval"];
      [defaults setObject: [NSNumber numberWithBool: YES] forKey: @"Autosave"];
      debugLevels = [[NSProcessInfo processInfo] debugSet];
      [debugLevels addObjectsFromArray: [[NSUserDefaults standardUserDefaults] 
            objectForKey: @"DebugLevels"]];

      [[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
      [[NSUserDefaults standardUserDefaults] synchronize];
}

- (id)init
{
      id logFile;
      id icon;
      id array;

      if((self = [super init]))
      {
            //redirect output
                  
            logFile = [[NSUserDefaults standardUserDefaults] stringForKey: @"LogFile"];
            if(![[NSFileManager defaultManager] isWritableFileAtPath: 
                  [logFile stringByDeletingLastPathComponent]])
            {
                  logFile = [[[NSUserDefaults standardUserDefaults] 
                              volatileDomainForName: NSRegistrationDomain]
                              valueForKey:@"LogFile"];
                  NSWarnLog(@"Invalid value for user default 'LogFile'. The specificed directory is not writable");
                  NSWarnLog(@"Switching to registered default %@", logFile);
            } 

            freopen([logFile cString], "w", stderr);

            //create the model controller
            modelController = [ULModelController new];

            //the methods to be forwarded to the 
            //active delegate.
            objectActions = [[NSArray alloc] initWithObjects:
                              @"cut:",
                              @"copy:",
                              @"paste:",
                              @"remove:",
                              @"export:",
                              @"import:",
                              @"deselectAllRows:",
                              nil];

            //simulation commands
            simulationCommands = [[NSArray alloc] initWithObjects:
                              @"halt:",
                              @"terminateProcess:",
                              @"execute:",
                              @"start:",
                              @"restart:",
                              nil]; 

            allowedActions = [NSMutableDictionary new];
            array = [NSArray arrayWithObjects: 
                        @"start:", 
                        @"remove:",
                        @"display:",
                        nil];
            [allowedActions setObject: array forKey: @"Waiting"];
            array = [NSArray arrayWithObjects: 
                        @"halt:", 
                        @"execute:",
                        @"terminateProcess:",
                        nil];
            [allowedActions setObject: array forKey: @"Running"];
            array = [NSArray arrayWithObjects: 
                        @"restart:", 
                        @"terminateProcess:",
                        nil];
            [allowedActions setObject: array forKey: @"Suspended"];
            array = [NSArray arrayWithObject: 
                        @"remove:"]; 
            [allowedActions setObject: array forKey: @"Finished"];

            //create the pasteboard 

            appPasteboard = [ULPasteboard new];

      }

      NSDebugLLog(@"ViewController", @"Completed initialisation");      

      return self;
}

- (void) awakeFromNib
{
      id columns;
      NSString* welcomeString;
      id item;
      NSMenu* mainMenu;

      [statusWindow center];
      [self _makeSplashScreen];

      [[NSApp mainMenu] setTitle:@"Adun"];

      preferencesPanel = [[ULPreferences alloc] initWithModelViewController: self];
      optionsViewController = [[ULOptionsViewController alloc]  initWithOptionsController: 
                        [modelController valueForKey:@"OptionsController"]
                        modelViewController: self];
      systemViewController = [[ULSystemViewController alloc]  initWithSystemController: 
                        [modelController valueForKey:@"SystemController"]
                        modelViewController: self];
      analyser = [[ULAnalyser alloc] initWithModelViewController: self];
      templateController = [[ULTemplateViewController alloc] init];
      processManager = [modelController valueForKey:@"ProcessManager"];

      activeDelegate = databaseBrowser;

      [selectHostButton removeAllItems];
      [selectHostButton addItemsWithTitles: [processManager valueForKey: @"Hosts"]];
      [selectHostButton selectItemAtIndex: 0];

      //register for notifications

      [[NSNotificationCenter defaultCenter] addObserver: self
            selector: @selector(handleServerDisconnection:)
            name: @"ULDisconnectedFromServerNotification"
            object: nil];
      [[NSNotificationCenter defaultCenter] addObserver: self
            selector: @selector(databaseBrowserBecameActive:)
            name: @"ULDatabaseBrowserDidBecomeActiveNotification"
            object: databaseBrowser];
      [[NSNotificationCenter defaultCenter] addObserver: self
            selector: @selector(statusTableBecameActive:)
            name: @"ULStatusTableDidBecomeActiveNotification"
            object: statusTable];
      [[NSNotificationCenter defaultCenter] addObserver: self
            selector: @selector(userLandFinishedProcess:)
            name: @"ULProcessDidFinishNotification"
            object: processManager];

      [statusWindow setDelegate: self];
      welcomeString = [NSString stringWithFormat: @"\nWelcome %@.\nWorking directory is %@\n\n",
                   NSFullUserName(), [[ULIOManager appIOManager] applicationDir]];
      [self logString: welcomeString newline: YES];
      [self logString: @"-------------------------------------------------------------------------\n"
                  newline: YES];

      [statusTable setProcessManager: processManager];
}

- (void)dealloc
{
      [databaseBrowser release];
      [statusTable release];
      [appPasteboard release];
      [templateController release];
      [preferencesPanel release];
      [optionsViewController release];
      [analyser release];
      [modelController release];
      [simulationCommands release];
      [optionsViewController release];
      [objectActions release];
      [allowedActions release];
      [super dealloc];
}

- (void) applicationDidFinishLaunching:(NSNotification *)aNotification
{
      NSPort* port;
      NSMutableDictionary* userInfo;

      [self closeCreateSimulationWindow: self];

      //check now if there is a local instance of AdunServer running

      if((port = [[NSMessagePortNameServer sharedInstance] portForName: @"AdunServer"]) == nil)
            port = [[NSSocketPortNameServer sharedInstance] portForName: @"AdunServer" onHost: nil];
            
      //if there is no AdunServer listening locally alert the user and ask if they want one to be started

      if(port == nil)
            [self startAdunServer];
      
      [splashScreen orderOut: self];
      [splashScreen close];
      [splashScreenImageView release];
      [statusWindow makeKeyAndOrderFront: self];
}

- (BOOL)applicationShouldTerminate:(id)sender
{
      return YES;
}

- (void)applicationWillTerminate:(NSNotification *)aNotif
{
      //save the database
      
      [modelController saveDatabase];
      //FIXME: Seems to be necessary - However we disable for now since
      //there is a bug in one objects dealloc method which hasnt been
      //found yet
      //[self autorelease];
}

- (BOOL)application:(NSApplication *)application openFile:(NSString *)fileName
{
}

- (void)showPrefPanel:(id)sender
{
      [preferencesPanel showPreferences: self];
}

/**
StatusTable / DatabaseBrowser directing
*/

00292 - (void) databaseBrowserBecameActive: (NSNotification*) aNotification
{
      [statusTable setActive: NO];
      [databaseBrowser setActive: YES];
      activeDelegate = databaseBrowser;
}

- (void) statusTableBecameActive: (NSNotification*) aNotification
{
      [databaseBrowser setActive: NO];
      [statusTable setActive: YES];
      activeDelegate = statusTable;
}

/**
AdunServer launching 
**/

00310 - (void) startAdunServer
{
      int retVal;
      NSString* launchPath;

      retVal = NSRunAlertPanel(@"Alert", 
                  @"There is no AdunServer running on the local host.\nDo you wish me to start one now?\n", 
                  @"Yes",
                  @"No", 
                  nil);

      if(retVal == NSOKButton)
      {
            launchPath = [NSHomeDirectory() 
                        stringByAppendingPathComponent: @"GNUstep/Tools/AdunServer"];

            NS_DURING
            {
                  [NSTask launchedTaskWithLaunchPath: launchPath
                        arguments: nil];
            }
            NS_HANDLER
            {
                  NSRunAlertPanel(@"Alert",
                        [NSString stringWithFormat: @"Unable to lauch AdunServer - %@",
                              [localException reason]],
                        @"Dismiss", 
                        nil,
                        nil);
            }
            NS_ENDHANDLER
      }
}

- (void) handleServerDisconnection: (NSNotification*) aNotification
{
      NSString *errorString;
      NSError * error;
      NSString* disconnectedHost;
      NSDictionary* userInfo;

      userInfo = [aNotification userInfo];

      error = [userInfo objectForKey: @"ULDisconnectionErrorKey"];
      disconnectedHost = [userInfo objectForKey: @"ULDisconnectedHostKey"];

      //display the error

      errorString = [NSString stringWithFormat: @"%@\n\n%@", 
                  [[error userInfo] objectForKey: NSLocalizedDescriptionKey],
                  [[error userInfo] objectForKey: @"NSLocalizedRecoverySuggestionKey"]];

      [self logString: errorString newline: YES];
      NSRunAlertPanel(@"Error", errorString, @"Dismiss", nil, nil);

      //if the server that died was the local server attempt to restart it

      if([disconnectedHost isEqual: [[NSHost currentHost] name]])
            [self startAdunServer];
}

//Check the termination status of all simulations
- (void) userLandFinishedProcess: (NSNotification*) aNotification
{
      NSError* terminationError;
      NSMutableString* logString;
      NSString* errorString;

      terminationError = [[aNotification userInfo] objectForKey: @"AdTerminationErrorKey"];
      
      if(terminationError != nil)
      {
            NSRunAlertPanel(@"Simulation Error",
                  [NSString stringWithFormat: @"%@\nSee log for more details.\n", 
                        [[terminationError userInfo] objectForKey: @"NSLocalizedDescriptionKey"]],
                        @"Dismiss",
                        nil,
                        nil);
            
            //check if we have a detailed description or a recovery suggestion      

            logString = [NSMutableString stringWithCapacity: 1];
            
            if((errorString = [[terminationError userInfo] objectForKey: @"AdDetailedDescriptionKey"]) != nil)
                  [logString appendFormat: @"%@", errorString];

            if((errorString = [[terminationError userInfo] objectForKey: @"NSRecoverySuggestionKey"]) != nil)
                  [logString appendFormat: @"%@", errorString];

            if([logString isEqual: @""])
            {
                  [logString appendString: 
                        [[terminationError userInfo] objectForKey: @"NSLocalizedDescriptionKey"]];
                  [logString appendString: @"\nNo extra details available on cause of termination\n"];
            }
            else
                  [logString insertString: 
                        [[terminationError userInfo] objectForKey: @"NSLocalizedDescriptionKey"]
                        atIndex: 0];

            [self logString: [NSString stringWithFormat: @"Simulation exited unexpectedly.\n%@\n", logString]
                  newline: YES
                  forProcess: [[aNotification userInfo] 
                        objectForKey: @"ULTerminatedProcess"]];
      }
      else
      {
            [self logString: @"Simulation finished successfully\n" 
                  newline: YES 
                  forProcess: [[aNotification userInfo] 
                        objectForKey: @"ULTerminatedProcess"]];
      }
}

//Logging

- (void) logString: (NSString*) string newline: (BOOL) newline
{
      NSRange endRange;

      endRange.location = 0;
      endRange.length = 0;
      [logOutput replaceCharactersInRange:endRange withString: string];
}

- (void) logString: (NSString*) string newline: (BOOL) newline forProcess: (ULProcess*) process
{
      NSString* processString;
      NSRange endRange;

      [self logString: string newline: newline]; 

      endRange.location = 0;
      endRange.length = 0;
      processString = [NSString stringWithFormat: @"Simulation - Name: %@. PID: %@.\n\n", 
                        [process valueForKey: @"name"], [process valueForKey:@"processIdentifier"]];
      [logOutput replaceCharactersInRange:endRange withString: processString];
      endRange.location = 0;
      endRange.length = 0;
      [logOutput replaceCharactersInRange:endRange withString: 
            @"\n-------------------------------------------------------------------------\n"];

}

//Opening other windows

- (void) openAnalyser: (id) sender
{
      [analyser open: self];
}

- (void) newOptions: (id) sender
{
      [optionsViewController newOptions: (id) sender];
}

- (void) newSystem: (id) sender
{
      [systemViewController open: (id) sender];
}

- (void) testWindow: (id) sender
{
      [templateController open: self];
}

/**
Keys for the other view controllers to access the models
FIXME: In process of being deprecated
**/

00481 - (id) SystemController
{
      return [modelController valueForKey:@"SystemController"];
}

- (id) ProcessManager
{
      return [modelController valueForKey:@"ProcessManager"];
}

- (id) metadataController
{
      return optionsViewController;
}

/**
Menu validation 
*/

//the simulation commands are in a separate category
//but we validate them here
00502 - (BOOL) validateSimulationCommand: (NSString*) command
{
      id selectedItem;  
      NSString *status;

      if(![[appPasteboard availableTypes] containsObject: @"ULProcess"])
            return NO;

      if([appPasteboard countOfObjectsForType: @"ULProcess"] != 1)
            return NO;
                  
      status = [[[appPasteboard objectsForType: @"ULProcess"] 
                  objectAtIndex: 0] 
                  processStatus];
      
      if([[allowedActions objectForKey: status] 
            containsObject: command])
            return YES;
      else
            return NO;

      return YES;
}

- (BOOL) validateMenuItem: (NSMenuItem*) menuItem
{
      NSString* action;
      id object, objectType;
      ULPasteboard* pasteboard = [ULPasteboard appPasteboard];


      action = NSStringFromSelector([menuItem action]);
      if([objectActions containsObject: action])
            return [activeDelegate validateMenuItem: menuItem];

      if([simulationCommands containsObject: action])
            return [self validateSimulationCommand: action];

      if([action isEqual: @"properties:"])
            return [optionsViewController validateMenuItem: menuItem];

      if([action isEqual: @"analyse:"])
            return [analyser validateMenuItem: menuItem];

      if([action isEqual: @"display:"])
      {
            //FIXME: Everything should be displayable
            objectType = [[pasteboard availableTypes] objectAtIndex: 0];
            if([objectType isEqual: @"AdDataSet"] || 
                  [objectType isEqual: @"ULOptions"] || 
                  [objectType isEqual: @"ULProcess"])
            {     
                  return YES;
            }     
            else
                  return NO;

      }

      //FIXME: preliminary load validation - load: only works
      //with simulation creation at the moment
      if([action isEqual: @"load:"])
      {
            if([activeDelegate countOfObjectsForType: @"ULSystem"] > 0)
                  return YES;
            else if([activeDelegate countOfObjectsForType: @"ULOptions"] > 0)
                  return YES;
            else
                  return NO;
      }           

      return YES;
}

//Delegate to the activeDelegate
//We could avoid doing this by subclassing the outline and table views
//the delegates use and override/add these methods. This would 
//simplify things even more. However for now will stick with this
//method as there are more pressing things to do.

- (void) cut: (id) sender 
{     
      [activeDelegate cut: sender];
 }

- (void) copy: (id) sender 
{ 
      [activeDelegate copy: sender]; 
}

- (void) paste: (id) sender 
{ 
      [activeDelegate paste: sender]; 
}

- (void) remove: (id) sender 
{ 
      [activeDelegate remove: sender]; 
}

- (void) export: (id) sender
{
      [activeDelegate export: self];
}

- (void) import: (id) sender
{
      [activeDelegate import: self];
}

- (void) deselectAllRows: (id) sender
{
      [activeDelegate deselectAllRows: self];
}

/**
Delegate to other tools
**/

//FIXME: Should you be able to edit options??
00622 - (void) display: (id) sender 
{
      ULPasteboard* pasteboard = [ULPasteboard appPasteboard];
      NSString* objectType;
      
      objectType = [[pasteboard availableTypes] objectAtIndex: 0];

      if([objectType isEqual: @"ULProcess"] || 
            [objectType isEqual: @"ULOptions"])
            [optionsViewController display: self]; 
      else
            [analyser display: self];
}

- (void) properties: (id) sender
{
      [optionsViewController properties: self];
}

- (void) analyse: (id) sender
{
      [analyser analyse: self];
}


//On closing the main window the application should quit
//but i'm not sure if calling applicationShouldTerminate 
//here is a good idea.

- (BOOL) windowShouldClose: (id) sender
{
      return NO;
}

@end

//This category will evolve to a full object

@implementation ViewController (SimulationCreation)

- (void) createProcess: (id) sender
{
      [createSimulationWindow setLevel: NSFloatingWindowLevel];
      [createSimulationWindow center];
      [createSimulationWindow makeKeyAndOrderFront: self];
}

- (void) createNewSimulation: (id) sender
{
      [createSimulationWindow close];
      host = [selectHostButton titleOfSelectedItem];
      
      NS_DURING
      {
            [modelController createProcessWithSystem: [systems objectAtIndex: 0]
                  options: [options objectAtIndex: 0]
                  host: host];
      }
      NS_HANDLER
      {
            if([[localException name] isEqual: NSInternalInconsistencyException])
                  NSRunAlertPanel(@"Alert", [localException reason], @"Dismiss", nil, nil);
      }
      NS_ENDHANDLER
}

- (void) closeCreateSimulationWindow: (id) sender
{
      [createSimulationWindow close];
}

- (void) load: (id) sender
{
      if([activeDelegate countOfObjectsForType: @"ULSystem"] == 1)
      {
            [systems release];
            systems = [activeDelegate objectsForType: @"ULSystem"];
            [systems retain];
      }

      if([activeDelegate countOfObjectsForType: @"ULOptions"] == 1)
      {
            [options release];
            options = [activeDelegate objectsForType: @"ULOptions"];
            [options retain];
      }
      
      [optionsField setStringValue:
            [[options objectAtIndex: 0] valueForKey: @"name"]];
      [systemField setStringValue: 
            [[systems objectAtIndex: 0] valueForKey: @"name"]];
}

@end


Generated by  Doxygen 1.6.0   Back to index