Changeset 20330

Show
Ignore:
Timestamp:
06/26/07 14:55:36 (1 year ago)
Author:
patrick
Message:

Merges from the trunk related to Cocoa usage:

r20146: Eliminated the need for the class VrjApplicationController?. Now,

the actions for menu items go to the NSApplication delegate. This
makes things a lot simpler and should allow for some improved
design options.

r20147: Change the handling of the recently loaded configuration files so

that the list is always retained in an NSMutableArray. This at
least works around the current bug of the "Open Recent" submenu
not being updated correctly.

r20148: Store VR Juggler preferences in a dictionary so that we can keep

track of more than just the recently loaded configuration files.
For now, I have added a preference for setting the maximum number
of recently loaded configuration files to store.

r20149: Replaced a remaining direct call to vrj::Kernel::loadConfigFiles()

in VrjMainController? with a call to -kernelLoadConfigFile:.

r20150: Moved the code for loading user preferences and performing the

initial populating of the "Open Recent" submenu into the -init
method of VrjMainController?. This makes
-applicationDidFinishLaunching: much simpler.

r20151: Renamed VrjMainController? to VRJMainController and DummyThread? to

VRJDummyThread to be in line with Objective-C class naming
conventions.

r20152: VRJMainController is not an accurate name for the role played by

the class. For that reason, I have renamed it to VRJBasicDelegate
and changed the vrjuggler.plist key for using a different
NSApplication delegate type to VRJDelegateClass.

r20153: Move VRJBasicDelegate out of CocoaWrapper?.mm and into its own

interface and implementation files. This will allow user-level
code to derive from VRJBasicDelegate to create a custom
NSApplication delegate (if so desired).

The Cocoa work is still not done yet (at least as far as my goals for it are
concerned), but this gets it nearly all the way there. I had held off on
merging these changes from the trunk until the work was done, but now I would
rather get this into the 2.2 Beta 1 release and finish the last bits later.

Bumped the version to 2.1.29.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • juggler/branches/2.2/modules/vrjuggler/ChangeLog

    r20216 r20330  
    11DATE        AUTHOR      CHANGE 
    22----------- ----------- ------------------------------------------------------- 
     3Jun-26-2007 patrick     Exposed VRJBasicDelegate so that user-level code can 
     4                        derive from it to customize response to Cocoa events. 
     5                        NEW VERSION: 2.1.29 
    36May-14-2007 patrick     Finished making vrj::OpenSGApp work with both OpenSG 
    47                        1.x and 2.0. 
  • juggler/branches/2.2/modules/vrjuggler/VERSION

    r20216 r20330  
     12.1.29-0 @06/26/2007 19:55:00 UTC@ 
    122.1.28-0 @05/14/2007 20:50:00 UTC@ 
    232.1.27-0 @05/11/2007 20:20:00 UTC@ 
  • juggler/branches/2.2/modules/vrjuggler/data/bundle/MainMenu.nib/classes.nib

    r19884 r20330  
    11{ 
    2     IBClasses = ( 
    3         {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },  
    4         { 
    5             ACTIONS = {clearRecentDocuments = id; openConfiguration = id; };  
    6             CLASS = VrjApplicationController;  
    7             LANGUAGE = ObjC;  
    8             SUPERCLASS = NSObject;  
    9         } 
    10     );  
     2    IBClasses = ({CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; });  
    113    IBVersion = 1;  
    124} 
  • juggler/branches/2.2/modules/vrjuggler/data/bundle/MainMenu.nib/info.nib

    r19884 r20330  
    1919        </array> 
    2020        <key>IBSystem Version</key> 
    21         <string>8L127</string> 
     21        <string>8P135</string> 
    2222</dict> 
    2323</plist> 
  • juggler/branches/2.2/modules/vrjuggler/data/bundle/vrjuggler.plist

    r20000 r20330  
    55        <key>VRJConfigHandling</key> 
    66        <false/> 
    7         <key>VRJControllerClass</key> 
    8         <string>VrjMainController</string> 
     7        <key>VRJDelegateClass</key> 
     8        <string>VRJBasicDelegate</string> 
    99</dict> 
    1010</plist> 
  • juggler/branches/2.2/modules/vrjuggler/vrj/Kernel/CocoaWrapper.mm

    r20000 r20330  
    3131#include <objc/objc-runtime.h> 
    3232 
    33 #import <Foundation/NSValue.h> 
    3433#import <Foundation/NSObject.h> 
    3534#import <Foundation/NSBundle.h> 
     
    3736#import <Foundation/NSLock.h> 
    3837#import <Foundation/NSAutoreleasePool.h> 
    39 #import <Foundation/NSNotification.h> 
    40 #import <Foundation/NSPathUtilities.h> 
    4138#import <AppKit/NSApplication.h> 
    4239#import <Cocoa/Cocoa.h> 
     
    4643#include <gadget/Devices/KeyboardMouseDevice/InputAreaCocoa.h> 
    4744 
    48 #include <vrj/Kernel/Kernel.h> 
     45#import <vrj/Kernel/VRJBasicDelegate.h> 
    4946#include <vrj/Kernel/CocoaWrapper.h> 
    5047 
    5148 
    52 static NSMenu* getRecentFilesMenu() 
    53 
    54    NSMenu* files_menu = nil; 
    55    NSApplication* app = [NSApplication sharedApplication]; 
    56    NSMenuItem* item = [[app mainMenu] itemWithTitle:@"File"]; 
    57  
    58    if ( item ) 
    59    { 
    60       item = [[item submenu] itemWithTitle:@"Open Recent"]; 
    61  
    62       if ( item ) 
    63       { 
    64          files_menu = [item submenu]; 
    65       } 
    66    } 
    67  
    68    return files_menu; 
    69 
    70  
    71 static NSMenuItem* insertCfgFileItem(NSMenu* menu, NSString* title, 
    72                                      NSString* accel, const int index) 
    73 
    74 /* 
    75    NSMenuItem* item = [[NSMenuItem alloc] init]; 
    76    [item setTitle:title]; 
    77    [item setAction:@selector(loadConfigFile:)]; 
    78    [item setKeyEquivalent:accel]; 
    79    [menu insertItem:item 
    80             atIndex:index]; 
    81 */ 
    82    NSMenuItem* item = [menu insertItemWithTitle:title 
    83                                          action:@selector(loadConfigFile:) 
    84                                   keyEquivalent:accel 
    85                                         atIndex:index]; 
    86 /* 
    87    NSMenuItem* item = [menu addItemWithTitle:title 
    88                                       action:@selector(loadConfigFile:) 
    89                                keyEquivalent:accel]; 
    90 */ 
    91    [item setKeyEquivalentModifierMask:NSCommandKeyMask]; 
    92    NSLog(@"Inserted item %@ at index %d in menu %@\n", item, index, menu); 
    93  
    94    return item; 
    95 
    96  
    97 @interface VrjMainController : NSObject 
    98 
    99    BOOL      mLoadConfigs; 
    100    NSString* mRecentCfgFileName; 
    101 
    102  
    103    -(void) setLoadConfigs:(BOOL) load; 
    104    -(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication*) sencedr; 
    105    -(void) applicationWillFinishLaunching:(NSNotification*) aNotification; 
    106    -(void) applicationDidFinishLaunching:(NSNotification*) aNotification; 
    107    -(NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*) sender; 
    108    -(void) applicationWillTerminate:(NSNotification*) aNotification; 
    109    -(BOOL) application:(NSApplication*) theApplication 
    110               openFile:(NSString*) file; 
    111    -(BOOL) application:(NSApplication*) theApplication 
    112              openFiles:(NSArray*) files; 
    113    -(IBAction) loadConfigFile:(id) sender; 
    114 @end 
    115  
    116 @implementation VrjMainController 
    117    -(id) init 
    118    { 
    119       mLoadConfigs = YES; 
    120       mRecentCfgFileName = nil; 
    121       return [super init]; 
    122    } 
    123  
    124    -(void) setLoadConfigs:(BOOL) load 
    125    { 
    126       mLoadConfigs = load; 
    127    } 
    128  
    129    -(BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication*) sencedr 
    130    { 
    131       // We return NO here because we have a different way of shutting down 
    132       // the application. When vrj::Kernel::stop() is invoked, it will cause 
    133       // the application run loop to stop by invoking 
    134       // vrj::CocoaWrapper::stop(). 
    135       return NO; 
    136    } 
    137  
    138    -(void) applicationWillFinishLaunching:(NSNotification*) aNotification 
    139    { 
    140    } 
    141  
    142    -(void) applicationDidFinishLaunching:(NSNotification*) aNotification 
    143    { 
    144       NSFileManager* mgr = [NSFileManager defaultManager]; 
    145       NSArray* paths = 
    146          NSSearchPathForDirectoriesInDomains( 
    147             NSApplicationSupportDirectory, NSUserDomainMask, YES 
    148          ); 
    149  
    150       if ( [paths count] > 0 ) 
    151       { 
    152          NSString* app_dir = [paths objectAtIndex:0]; 
    153          NSString* vrj_app_dir = 
    154             [app_dir stringByAppendingPathComponent:@"VR Juggler"]; 
    155          [mgr createDirectoryAtPath:vrj_app_dir 
    156                          attributes:nil]; 
    157  
    158          mRecentCfgFileName = 
    159             [vrj_app_dir stringByAppendingPathComponent:@"recent_cfgs"]; 
    160          [mRecentCfgFileName retain]; 
    161       } 
    162  
    163       NSMenu* file_menu = getRecentFilesMenu(); 
    164  
    165       if ( file_menu ) 
    166       { 
    167          NSArray* cfg_files = 
    168             [NSArray arrayWithContentsOfFile:mRecentCfgFileName]; 
    169  
    170          if ( cfg_files ) 
    171          { 
    172             if ( [cfg_files count] > 0 ) 
    173             { 
    174                for ( unsigned int i = 0; i < [cfg_files count]; ++i ) 
    175                { 
    176                   NSString* fname = [cfg_files objectAtIndex:i];; 
    177                   NSString* accel = [NSString stringWithFormat:@"%d", i]; 
    178                   insertCfgFileItem(file_menu, fname, accel, i); 
    179                } 
    180             } 
    181          } 
    182       } 
    183  
    184       // We're ready to allow windows to open! 
    185       NSConditionLock* lock = gadget::InputAreaCocoa::getWindowLock(); 
    186       [lock unlock]; 
    187    } 
    188  
    189    -(NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*) sender 
    190    { 
    191       return NSTerminateNow; 
    192    } 
    193  
    194    /** 
    195     * Clean up before terminating. 
    196     */ 
    197    -(void) applicationWillTerminate:(NSNotification*) aNotification 
    198    { 
    199       NSMenu* menu = getRecentFilesMenu(); 
    200  
    201       if ( menu && mRecentCfgFileName ) 
    202       { 
    203          const int count = [menu numberOfItems]; 
    204          NSMutableArray* recent_files = 
    205             [NSMutableArray arrayWithCapacity:count]; 
    206  
    207          for ( int i = 0; i < count; ++i ) 
    208          { 
    209             NSMenuItem* item = [menu itemAtIndex:i]; 
    210  
    211             if ( [item isSeparatorItem] ) 
    212             { 
    213                break; 
    214             } 
    215          } 
    216  
    217          NSLog(@"Files: %@\n", recent_files); 
    218          [recent_files writeToFile:mRecentCfgFileName 
    219                         atomically:YES]; 
    220          [mRecentCfgFileName release]; 
    221       } 
    222  
    223       vrj::Kernel::instance()->stop(); 
    224  
    225       // NOTE: This call is to ensure that we wait for the kernel to stop 
    226       // completely before exiting the run loop. This is necessary to prevent 
    227       // race conditions on shutdown caused by the default NSApplication run 
    228       // method implementation calling exit(3) which in turn causes the Juggler 
    229       // singletons to be deleted. We do not want that to happen until after 
    230       // the kernel has stopped itself. 
    231       vrj::Kernel::instance()->doWaitForKernelStop(); 
    232    } 
    233  
    234    -(BOOL) application:(NSApplication*) theApplication 
    235               openFile:(NSString*) file 
    236    { 
    237       if ( mLoadConfigs ) 
    238       { 
    239          vrj::Kernel::instance()->loadConfigFile([file UTF8String]); 
    240       } 
    241  
    242       return YES; 
    243    } 
    244  
    245    -(BOOL) application:(NSApplication*) theApplication 
    246              openFiles:(NSArray*) files 
    247    { 
    248       if ( mLoadConfigs ) 
    249       { 
    250          const int count = [files count]; 
    251          for ( int i = 0; i < count; ++i ) 
    252          { 
    253             NSString* file = [files objectAtIndex:i]; 
    254             vrj::Kernel::instance()->loadConfigFile([file UTF8String]); 
    255          } 
    256       } 
    257  
    258       return YES; 
    259    } 
    260  
    261    -(IBAction) loadConfigFile:(id) sender 
    262    { 
    263       vrj::Kernel::instance()->loadConfigFile([[sender title] UTF8String]); 
    264    } 
    265 @end 
    266  
    267 @interface DummyThread : NSObject 
     49@interface VRJDummyThread : NSObject 
    26850   +(void) run:(id) obj; 
    26951@end 
    27052 
    271 @implementation DummyThread 
     53@implementation VRJDummyThread 
    27254   +(void) run:(id) obj 
    27355   { 
    27456      /* Do nothing. */ ; 
    275    } 
    276 @end 
    277  
    278 @interface VrjApplicationController : NSObject 
    279 { 
    280    NSString* mLastDir; 
    281 } 
    282  
    283    -(IBAction) openConfiguration:(id) sender; 
    284    -(IBAction) clearRecentDocuments:(id) sender; 
    285 @end 
    286  
    287 @implementation VrjApplicationController 
    288    -(IBAction) openConfiguration:(id) sender 
    289    { 
    290       NSArray* file_types = [NSArray arrayWithObject:@"jconf"]; 
    291       NSOpenPanel* panel = [NSOpenPanel openPanel]; 
    292  
    293       [panel setAllowsMultipleSelection:YES]; 
    294  
    295       if ( ! mLastDir ) 
    296       { 
    297          mLastDir = NSHomeDirectory(); 
    298          [mLastDir retain]; 
    299       } 
    300  
    301       const int result = [panel runModalForDirectory:mLastDir 
    302                                                 file:nil 
    303                                                types:file_types]; 
    304  
    305       if ( result == NSOKButton ) 
    306       { 
    307          [mLastDir release]; 
    308          mLastDir = [panel directory]; 
    309          [mLastDir retain]; 
    310  
    311          NSMenu* files_menu = getRecentFilesMenu(); 
    312  
    313          NSArray* files = [panel filenames]; 
    314          int count = [files count]; 
    315          for ( int i = 0; i < count; ++i ) 
    316          { 
    317             NSString* file = [files objectAtIndex:i]; 
    318             vrj::Kernel::instance()->loadConfigFile([file UTF8String]); 
    319  
    320             // TODO: Make this limit controlled by user preferences. 
    321             // NOTE: The value 12 accounts for the separator item and the 
    322             // "Clear Menu" item after the separator. 
    323             if ( files_menu && [files_menu numberOfItems] > 12 ) 
    324             { 
    325                [files_menu removeItemAtIndex:0]; 
    326  
    327                for ( int i = 0; i < 9; ++i ) 
    328                { 
    329                   NSMenuItem* item = [files_menu itemAtIndex:i]; 
    330                   NSString* equiv = [NSString stringWithFormat:@"%d", i]; 
    331                   [item setKeyEquivalent:equiv]; 
    332                } 
    333             } 
    334  
    335             if ( files_menu ) 
    336             { 
    337                const int index = [files_menu indexOfItemWithTitle:file]; 
    338  
    339                if ( index == -1 ) 
    340                { 
    341                   int insert_index(0); 
    342  
    343                   for ( int i = 0; i < [files_menu numberOfItems]; ++i ) 
    344                   { 
    345                      NSMenuItem* item = [files_menu itemAtIndex:i]; 
    346  
    347                      if ( [item isSeparatorItem] ) 
    348                      { 
    349                         insert_index = i - 1; 
    350                         break; 
    351                      } 
    352                   } 
    353  
    354                   NSString* equiv = 
    355                      [NSString stringWithFormat:@"%d", insert_index]; 
    356                   insertCfgFileItem(files_menu, file, equiv, insert_index); 
    357                } 
    358             } 
    359          } 
    360       } 
    361    } 
    362  
    363    -(IBAction) clearRecentDocuments:(id) sender 
    364    { 
    365       NSMenu* menu = [sender menu]; 
    366       const int init_size = [menu numberOfItems]; 
    367  
    368       for ( int i = 0; i < init_size; ++i ) 
    369       { 
    370          NSMenuItem* item = [menu itemAtIndex:0]; 
    371  
    372          if ( [item isSeparatorItem] ) 
    373          { 
    374             break; 
    375          } 
    376          else 
    377          { 
    378             [menu removeItem:item]; 
    379          } 
    380       } 
    38157   } 
    38258@end 
     
    40682   // application. 
    40783   [NSThread detachNewThreadSelector:@selector(run:) 
    408                             toTarget:[DummyThread class] 
     84                            toTarget:[VRJDummyThread class] 
    40985                          withObject:nil]; 
    41086   assert([NSThread isMultiThreaded]); 
     
    429105   // application:openFile: and application:openFiles: messages. 
    430106   BOOL load_cfg_files = YES; 
    431    NSString* ctrl_class_name = @"VrjMainController"; 
     107   NSString* ctrl_class_name = @"VRJBasicDelegate"; 
    432108 
    433109   if ( vrj_dict ) 
     
    440116      } 
    441117 
    442       NSString* name = [vrj_dict objectForKey:@"VRJControllerClass"]; 
     118      NSString* name = [vrj_dict objectForKey:@"VRJDelegateClass"]; 
    443119 
    444120      if ( nil != name ) 
     
    453129   { 
    454130      NSLog(@"WARNING: Could not find declaration of %@!\n", ctrl_class_name); 
    455       NSLog(@"         Falling back on VrjMainController\n"); 
    456       controller_class = [VrjMainController class]; 
     131      NSLog(@"         Falling back on VRJBasicDelegate\n"); 
     132      controller_class = [VRJBasicDelegate class]; 
    457133   } 
    458134 
  • juggler/branches/2.2/modules/vrjuggler/vrj/Kernel/Makefile.in

    r19902 r20330  
    5050ifeq (@PLATFORM@, Darwin) 
    5151   ifeq (@GADGET_USE_COCOA@, yes) 
    52       SRCS+=    CocoaWrapper.mm 
     52      SRCS+=    CocoaWrapper.mm         \ 
     53                VRJBasicDelegate.mm 
    5354   endif 
    5455endif 
  • juggler/branches/2.2/modules/vrjuggler/vrjuggler.fpc.in

    r19920 r20330  
    7171extra_libs : ${extra_libs} 
    7272static_libs: ${static_begin} ${vrj_ldflags} ${vrj_libs} ${static_end} 
    73 profiled_libs: ${vrj_ldflags} ${vrj_prof_libs} 
     73profiled_libs: ${vrj_ldflags} ${vrj_prof_libs} ${extra_libs} 
    7474profiled_static_libs: ${static_begin} ${vrj_ldflags} ${vrj_prof_libs} ${static_end} 
    7575