| 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 | | |
|---|
| | 75 | |
|---|
| | 76 | /** |
|---|
| | 77 | * Loads the named VR Juggler configuration file using |
|---|
| | 78 | * vrj::Kernel::loadConfigFile(). |
|---|
| | 79 | */ |
|---|
| | 80 | -(void) kernelLoadConfigFile:(NSString*) fileName; |
|---|
| | 81 | |
|---|
| | 82 | /** |
|---|
| | 83 | * Returns a pointer to the NSMenu object that is the submenu listing the |
|---|
| | 84 | * recently loaded configuration files or nil if no such submenu exists. |
|---|
| | 85 | * In other words, this returns the File -> Open Recent submenu object. |
|---|
| | 86 | * This is a convenice method. |
|---|
| | 87 | */ |
|---|
| | 88 | -(NSMenu*) getRecentFilesMenu; |
|---|
| | 89 | |
|---|
| | 90 | -(NSMenuItem*) insertCfgFileItem:(NSString*) title |
|---|
| | 91 | accel:(NSString*) accel |
|---|
| | 92 | index:(int) index; |
|---|
| | 232 | [self kernelLoadConfigFile:[files objectAtIndex:i]]; |
|---|
| | 233 | } |
|---|
| | 234 | } |
|---|
| | 235 | |
|---|
| | 236 | return YES; |
|---|
| | 237 | } |
|---|
| | 238 | |
|---|
| | 239 | -(IBAction) loadConfigFile:(id) sender |
|---|
| | 240 | { |
|---|
| | 241 | [self kernelLoadConfigFile:[sender title]]; |
|---|
| | 242 | } |
|---|
| | 243 | |
|---|
| | 244 | -(void) kernelLoadConfigFile:(NSString*) fileName |
|---|
| | 245 | { |
|---|
| | 246 | // Load the configuration file. |
|---|
| | 247 | vrj::Kernel::instance()->loadConfigFile([fileName UTF8String]); |
|---|
| | 248 | |
|---|
| | 249 | // Update the submenu listing the recently opened configuration files |
|---|
| | 250 | // to include fileName. |
|---|
| | 251 | NSMenu* files_menu = [self getRecentFilesMenu]; |
|---|
| | 252 | |
|---|
| | 253 | // NOTE: The 12 accounts for the separator item and the "Clear Menu" |
|---|
| | 254 | // item after the separator. |
|---|
| | 255 | if ( files_menu && [files_menu numberOfItems] > 12 ) |
|---|
| | 256 | { |
|---|
| | 257 | [files_menu removeItemAtIndex:0]; |
|---|
| | 258 | |
|---|
| | 259 | for ( int i = 0; i < 9; ++i ) |
|---|
| | 260 | { |
|---|
| | 261 | NSMenuItem* item = [files_menu itemAtIndex:i]; |
|---|
| | 262 | [item setKeyEquivalent:[NSString stringWithFormat:@"%d", i]]; |
|---|
| | 263 | } |
|---|
| | 264 | } |
|---|
| | 265 | |
|---|
| | 266 | if ( files_menu ) |
|---|
| | 267 | { |
|---|
| | 268 | const int index = [files_menu indexOfItemWithTitle:fileName]; |
|---|
| | 269 | |
|---|
| | 270 | if ( index == NSNotFound ) |
|---|
| | 271 | { |
|---|
| | 272 | int insert_index(0); |
|---|
| | 273 | const int count = [files_menu numberOfItems]; |
|---|
| | 274 | |
|---|
| | 275 | for ( int i = 0; i < count; ++i ) |
|---|
| | 276 | { |
|---|
| | 277 | NSMenuItem* item = [files_menu itemAtIndex:i]; |
|---|
| | 278 | |
|---|
| | 279 | if ( [item isSeparatorItem] ) |
|---|
| | 280 | { |
|---|
| | 281 | insert_index = i - 1; |
|---|
| | 282 | break; |
|---|
| | 283 | } |
|---|
| | 284 | } |
|---|
| | 285 | |
|---|
| | 286 | [self insertCfgFileItem:fileName |
|---|
| | 287 | accel:[NSString stringWithFormat:@"%d", 0] |
|---|
| | 288 | index:insert_index]; |
|---|
| | 289 | } |
|---|
| | 290 | } |
|---|
| | 291 | } |
|---|
| | 292 | |
|---|
| | 293 | /** |
|---|
| | 294 | * Receives the message sent by the File -> Open menu item. An NSOpenPanel |
|---|
| | 295 | * is displayed, and if the user clicks the OK button, the selected .jconf |
|---|
| | 296 | * file(s) is (are) loaded. |
|---|
| | 297 | * |
|---|
| | 298 | * @post If the user clicks the OK button, \c mLastDir has the name of the |
|---|
| | 299 | * directory where the opened panel was when it was closed. |
|---|
| | 300 | * |
|---|
| | 301 | * @see -kernelLoadConfigFile: |
|---|
| | 302 | */ |
|---|
| | 303 | -(IBAction) openDocument:(id) sender |
|---|
| | 304 | { |
|---|
| | 305 | NSArray* file_types = [NSArray arrayWithObject:@"jconf"]; |
|---|
| | 306 | NSOpenPanel* panel = [NSOpenPanel openPanel]; |
|---|
| | 307 | |
|---|
| | 308 | [panel setAllowsMultipleSelection:YES]; |
|---|
| | 309 | |
|---|
| | 310 | if ( ! mLastDir ) |
|---|
| | 311 | { |
|---|
| | 312 | mLastDir = NSHomeDirectory(); |
|---|
| | 313 | [mLastDir retain]; |
|---|
| | 314 | } |
|---|
| | 315 | |
|---|
| | 316 | const int result = [panel runModalForDirectory:mLastDir |
|---|
| | 317 | file:nil |
|---|
| | 318 | types:file_types]; |
|---|
| | 319 | |
|---|
| | 320 | if ( result == NSOKButton ) |
|---|
| | 321 | { |
|---|
| | 322 | [mLastDir release]; |
|---|
| | 323 | mLastDir = [panel directory]; |
|---|
| | 324 | [mLastDir retain]; |
|---|
| | 325 | |
|---|
| | 326 | NSArray* files = [panel filenames]; |
|---|
| | 327 | const unsigned int count = [files count]; |
|---|
| | 328 | |
|---|
| | 329 | for ( unsigned int i = 0; i < count; ++i ) |
|---|
| | 330 | { |
|---|
| 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]); |
|---|
| | 332 | [self kernelLoadConfigFile:file]; |
|---|
| | 333 | } |
|---|
| | 334 | } |
|---|
| | 335 | } |
|---|
| | 336 | |
|---|
| | 337 | /** |
|---|
| | 338 | * Receives the message sent by the "Clear Menu" item in the |
|---|
| | 339 | * File -> Open Recent submenu. |
|---|
| | 340 | * |
|---|
| | 341 | * @post \c mRecentCfgFiles is empty. |
|---|
| | 342 | */ |
|---|
| | 343 | -(IBAction) clearRecentDocuments:(id) sender |
|---|
| | 344 | { |
|---|
| | 345 | NSMenu* menu = [sender menu]; |
|---|
| | 346 | const int init_size = [menu numberOfItems]; |
|---|
| | 347 | |
|---|
| | 348 | for ( int i = 0; i < init_size; ++i ) |
|---|
| | 349 | { |
|---|
| | 350 | NSMenuItem* item = [menu itemAtIndex:0]; |
|---|
| | 351 | |
|---|
| | 352 | if ( [item isSeparatorItem] || |
|---|
| | 353 | [[item title] isEqualToString:@"Clear Menu"] ) |
|---|
| | 354 | { |
|---|
| | 355 | break; |
|---|
| | 356 | } |
|---|
| | 357 | else |
|---|
| | 358 | { |
|---|
| | 359 | [menu removeItem:item]; |
|---|
| | 360 | } |
|---|
| | 361 | } |
|---|
| | 362 | } |
|---|
| | 363 | |
|---|
| | 364 | -(NSMenu*) getRecentFilesMenu |
|---|
| | 365 | { |
|---|
| | 366 | NSMenu* files_menu = nil; |
|---|
| | 367 | NSApplication* app = [NSApplication sharedApplication]; |
|---|
| | 368 | NSMenuItem* item = [[app mainMenu] itemWithTitle:@"File"]; |
|---|
| | 369 | |
|---|
| | 370 | if ( item ) |
|---|
| | 371 | { |
|---|
| | 372 | item = [[item submenu] itemWithTitle:@"Open Recent"]; |
|---|
| | 373 | |
|---|
| | 374 | if ( item ) |
|---|
| | 375 | { |
|---|
| | 376 | files_menu = [item submenu]; |
|---|
| | 377 | } |
|---|
| | 378 | } |
|---|
| | 379 | |
|---|
| | 380 | return files_menu; |
|---|
| | 381 | } |
|---|
| | 382 | |
|---|
| | 383 | -(NSMenuItem*) insertCfgFileItem:(NSString*) title |
|---|
| | 384 | accel:(NSString*) accel |
|---|
| | 385 | index:(int) index |
|---|
| | 386 | { |
|---|
| | 387 | NSMenu* menu = [self getRecentFilesMenu]; |
|---|
| | 388 | NSMenuItem* item = [menu insertItemWithTitle:title |
|---|
| | 389 | action:@selector(loadConfigFile:) |
|---|
| | 390 | keyEquivalent:accel |
|---|
| | 391 | atIndex:index]; |
|---|
| | 392 | [item setKeyEquivalentModifierMask:NSCommandKeyMask]; |
|---|
| | 393 | NSLog(@"Inserted item %@ at index %d in menu %@\n", item, index, menu); |
|---|
| | 394 | |
|---|
| | 395 | return item; |
|---|
| 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 | | } |
|---|