| | 376 | @implementation MVChatScriptPlugin (MVChatPluginContextualMenuSupport) |
|---|
| | 377 | - (IBAction) performContextualMenuItemAction:(id) sender { |
|---|
| | 378 | id object = [sender representedObject]; |
|---|
| | 379 | NSMutableArray *submenu = [NSMutableArray array]; |
|---|
| | 380 | |
|---|
| | 381 | NSMenu *menu = [sender menu]; |
|---|
| | 382 | NSMenu *parent = nil; |
|---|
| | 383 | while( ( parent = [menu supermenu] ) ) { |
|---|
| | 384 | [submenu insertObject:[menu title] atIndex:0]; |
|---|
| | 385 | menu = parent; |
|---|
| | 386 | } |
|---|
| | 387 | |
|---|
| | 388 | NSString *title = [sender title]; |
|---|
| | 389 | NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys:title, @"----", object, @"pcM1", submenu, @"pcM2", nil]; |
|---|
| | 390 | [self callScriptHandler:'pcMX' withArguments:args forSelector:_cmd]; |
|---|
| | 391 | } |
|---|
| | 392 | |
|---|
| | 393 | - (void) buildMenuInto:(NSMutableArray *) itemList fromReturnContainer:(id) container withRepresentedObject:(id) object { |
|---|
| | 394 | if( [container respondsToSelector:@selector( objectEnumerator )] ) { |
|---|
| | 395 | NSEnumerator *enumerator = [container objectEnumerator]; |
|---|
| | 396 | id item = nil; |
|---|
| | 397 | |
|---|
| | 398 | while( ( item = [enumerator nextObject] ) ) { |
|---|
| | 399 | if( [item isKindOfClass:[NSString class]] ) { |
|---|
| | 400 | if( [item isEqualToString:@"-"] ) { |
|---|
| | 401 | [itemList addObject:[NSMenuItem separatorItem]]; |
|---|
| | 402 | } else { |
|---|
| | 403 | NSMenuItem *mitem = [[[NSMenuItem alloc] initWithTitle:item action:@selector( performContextualMenuItemAction: ) keyEquivalent:@""] autorelease]; |
|---|
| | 404 | [mitem setTarget:self]; |
|---|
| | 405 | [mitem setRepresentedObject:object]; |
|---|
| | 406 | [itemList addObject:mitem]; |
|---|
| | 407 | } |
|---|
| | 408 | } else if( [item isKindOfClass:[NSDictionary class]] ) { |
|---|
| | 409 | NSString *title = [item objectForKey:@"title"]; |
|---|
| | 410 | NSArray *sub = [item objectForKey:@"submenu"]; |
|---|
| | 411 | NSNumber *enabled = [item objectForKey:@"enabled"]; |
|---|
| | 412 | NSNumber *checked = [item objectForKey:@"checked"]; |
|---|
| | 413 | NSNumber *indent = [item objectForKey:@"indent"]; |
|---|
| | 414 | NSNumber *alternate = [item objectForKey:@"alternate"]; |
|---|
| | 415 | NSString *iconPath = [item objectForKey:@"icon"]; |
|---|
| | 416 | id iconSize = [item objectForKey:@"iconsize"]; |
|---|
| | 417 | NSString *tooltip = [item objectForKey:@"tooltip"]; |
|---|
| | 418 | id context = [item objectForKey:@"context"]; |
|---|
| | 419 | |
|---|
| | 420 | if( ! [title isKindOfClass:[NSString class]] ) continue; |
|---|
| | 421 | if( ! [tooltip isKindOfClass:[NSString class]] ) tooltip = nil; |
|---|
| | 422 | if( ! [enabled isKindOfClass:[NSNumber class]] ) enabled = nil; |
|---|
| | 423 | if( ! [checked isKindOfClass:[NSNumber class]] ) checked = nil; |
|---|
| | 424 | if( ! [indent isKindOfClass:[NSNumber class]] ) indent = nil; |
|---|
| | 425 | if( ! [alternate isKindOfClass:[NSNumber class]] ) alternate = nil; |
|---|
| | 426 | if( ! [iconPath isKindOfClass:[NSString class]] ) iconPath = nil; |
|---|
| | 427 | if( ! [iconSize isKindOfClass:[NSArray class]] && ! [iconSize isKindOfClass:[NSNumber class]] ) iconSize = nil; |
|---|
| | 428 | if( ! [sub isKindOfClass:[NSArray class]] && ! [sub isKindOfClass:[NSDictionary class]] ) sub = nil; |
|---|
| | 429 | |
|---|
| | 430 | NSMenuItem *mitem = [[[NSMenuItem alloc] initWithTitle:title action:@selector( performContextualMenuItemAction: ) keyEquivalent:@""] autorelease]; |
|---|
| | 431 | if( context ) [mitem setRepresentedObject:context]; |
|---|
| | 432 | else [mitem setRepresentedObject:object]; |
|---|
| | 433 | if( ! enabled || ( enabled && [enabled boolValue] ) ) [mitem setTarget:self]; |
|---|
| | 434 | if( enabled && ! [enabled boolValue] ) [mitem setEnabled:[enabled boolValue]]; |
|---|
| | 435 | if( checked ) [mitem setState:[checked intValue]]; |
|---|
| | 436 | if( indent ) [mitem setIndentationLevel:MIN( 15, [indent unsignedIntValue] )]; |
|---|
| | 437 | if( tooltip ) [mitem setToolTip:tooltip]; |
|---|
| | 438 | |
|---|
| | 439 | if( alternate && [alternate unsignedIntValue] == 1 ) { |
|---|
| | 440 | [mitem setKeyEquivalentModifierMask:NSAlternateKeyMask]; |
|---|
| | 441 | [mitem setAlternate:YES]; |
|---|
| | 442 | } else if( alternate && [alternate unsignedIntValue] == 2 ) { |
|---|
| | 443 | [mitem setKeyEquivalentModifierMask:( NSShiftKeyMask | NSAlternateKeyMask )]; |
|---|
| | 444 | [mitem setAlternate:YES]; |
|---|
| | 445 | } else if( alternate && [alternate unsignedIntValue] == 3 ) { |
|---|
| | 446 | [mitem setKeyEquivalentModifierMask:( NSShiftKeyMask | NSAlternateKeyMask | NSControlKeyMask )]; |
|---|
| | 447 | [mitem setAlternate:YES]; |
|---|
| | 448 | } |
|---|
| | 449 | |
|---|
| | 450 | if( [iconPath length] ) { |
|---|
| | 451 | NSURL *iconURL; |
|---|
| | 452 | if( iconURL = [NSURL URLWithString:iconPath] ) { |
|---|
| | 453 | // NSImage *icon = [[[NSImage allocWithZone:[self zone]] initByReferencingURL:[NSURL URLWithString:iconPath]] autorelease]; |
|---|
| | 454 | // Lets download the icon with a 1-second timeout |
|---|
| | 455 | // Let's also ask for the cache if it exists rather than using protocol default |
|---|
| | 456 | NSURLRequest *iconRequest = [NSURLRequest requestWithURL:iconURL cachePolicy:NSURLRequestReturnCacheDataElseLoad timeoutInterval:1.0]; |
|---|
| | 457 | NSData *iconData = [NSURLConnection sendSynchronousRequest:iconRequest returningResponse:nil error:nil]; |
|---|
| | 458 | NSImage *icon = [[[NSImage alloc] initWithData:iconData] autorelease]; |
|---|
| | 459 | if( icon ) [mitem setImage:icon]; |
|---|
| | 460 | } else { |
|---|
| | 461 | if( ! [iconPath isAbsolutePath] ) { |
|---|
| | 462 | NSString *dir = [[self scriptFilePath] stringByDeletingLastPathComponent]; |
|---|
| | 463 | iconPath = [dir stringByAppendingPathComponent:iconPath]; |
|---|
| | 464 | } |
|---|
| | 465 | |
|---|
| | 466 | NSImage *icon = [[[NSImage allocWithZone:[self zone]] initByReferencingFile:iconPath] autorelease]; |
|---|
| | 467 | if( icon ) [mitem setImage:icon]; |
|---|
| | 468 | } |
|---|
| | 469 | |
|---|
| | 470 | NSSize size = NSZeroSize; |
|---|
| | 471 | if( [iconSize isKindOfClass:[NSArray class]] && [(NSArray *)iconSize count] == 2 ) { |
|---|
| | 472 | size = NSMakeSize( [[iconSize objectAtIndex:0] unsignedIntValue], [[iconSize objectAtIndex:1] unsignedIntValue] ); |
|---|
| | 473 | } else if( [iconSize isKindOfClass:[NSNumber class]] ) { |
|---|
| | 474 | size = NSMakeSize( [iconSize unsignedIntValue], [iconSize unsignedIntValue] ); |
|---|
| | 475 | } |
|---|
| | 476 | |
|---|
| | 477 | if( [mitem image] && ! NSEqualSizes( size, NSZeroSize ) ) { |
|---|
| | 478 | [[mitem image] setScalesWhenResized:YES]; |
|---|
| | 479 | [[mitem image] setSize:size]; |
|---|
| | 480 | } |
|---|
| | 481 | } |
|---|
| | 482 | |
|---|
| | 483 | [itemList addObject:mitem]; |
|---|
| | 484 | |
|---|
| | 485 | if( [sub respondsToSelector:@selector( objectEnumerator )] && [sub respondsToSelector:@selector( count )] && [sub count] ) { |
|---|
| | 486 | NSMenu *submenu = [[[NSMenu allocWithZone:[self zone]] initWithTitle:title] autorelease]; |
|---|
| | 487 | NSMutableArray *subArray = [NSMutableArray array]; |
|---|
| | 488 | |
|---|
| | 489 | [self buildMenuInto:subArray fromReturnContainer:sub withRepresentedObject:object]; |
|---|
| | 490 | |
|---|
| | 491 | id subItem = nil; |
|---|
| | 492 | NSEnumerator *subenumerator = [subArray objectEnumerator]; |
|---|
| | 493 | while( ( subItem = [subenumerator nextObject] ) ) |
|---|
| | 494 | [submenu addItem:subItem]; |
|---|
| | 495 | |
|---|
| | 496 | [mitem setSubmenu:submenu]; |
|---|
| | 497 | } |
|---|
| | 498 | } |
|---|
| | 499 | } |
|---|
| | 500 | } |
|---|
| | 501 | } |
|---|
| | 502 | |
|---|
| | 503 | - (NSArray *) contextualMenuItemsForObject:(id) object inView:(id <JVChatViewController>) view { |
|---|
| | 504 | NSDictionary *args = [NSDictionary dictionaryWithObjectsAndKeys:object, @"----", view, @"cMi1", nil]; |
|---|
| | 505 | id result = [self callScriptHandler:'cMiX' withArguments:args forSelector:_cmd]; |
|---|
| | 506 | NSMutableArray *ret = [NSMutableArray array]; |
|---|
| | 507 | |
|---|
| | 508 | if( ! result ) return nil; |
|---|
| | 509 | if( ! [result isKindOfClass:[NSArray class]] ) |
|---|
| | 510 | result = [NSArray arrayWithObject:result]; |
|---|
| | 511 | |
|---|
| | 512 | [self buildMenuInto:ret fromReturnContainer:result withRepresentedObject:object]; |
|---|
| | 513 | |
|---|
| | 514 | if( [ret count] ) return ret; |
|---|
| | 515 | return nil; |
|---|
| | 516 | } |
|---|
| | 517 | @end |
|---|
| | 518 | |
|---|
| | 519 | #pragma mark - |
|---|
| | 520 | |
|---|