1 /* 2 Open Tracker License 3 4 Terms and Conditions 5 6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy of 9 this software and associated documentation files (the "Software"), to deal in 10 the Software without restriction, including without limitation the rights to 11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12 of the Software, and to permit persons to whom the Software is furnished to do 13 so, subject to the following conditions: 14 15 The above copyright notice and this permission notice applies to all licensees 16 and shall be included in all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25 Except as contained in this notice, the name of Be Incorporated shall not be 26 used in advertising or otherwise to promote the sale, use or other dealings in 27 this Software without prior written authorization from Be Incorporated. 28 29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30 of Be Incorporated in the United States and other countries. Other brand product 31 names are registered trademarks or trademarks of their respective holders. 32 All rights reserved. 33 */ 34 35 // PoseView scripting interface 36 37 #include <stdlib.h> 38 #include <stdio.h> 39 #include <string.h> 40 41 #include <ByteOrder.h> 42 #include <Debug.h> 43 #include <Message.h> 44 #include <PropertyInfo.h> 45 46 #include "Tracker.h" 47 #include "PoseView.h" 48 49 #define kPosesSuites "suite/vnd.Be-TrackerPoses" 50 51 #define kPropertyPath "Path" 52 53 #ifndef _SCRIPTING_ONLY 54 #if _SUPPORTS_FEATURE_SCRIPTING 55 #define _SCRIPTING_ONLY(x) x 56 #else 57 #define _SCRIPTING_ONLY(x) 58 #endif 59 #endif 60 61 // notes on PoseView scripting interface: 62 // Indices and entry_refs are used to specify poses; In the case of indices 63 // and previous/next specifiers the current PoseView sort order is used. 64 // If PoseView is not in list view mode, the order in which poses are indexed 65 // is arbitrary. 66 // Both of these specifiers, but indices more so, are likely to be accurate 67 // only untill a next change to the PoseView (a change may be adding, 68 // removing a pose, changing an attribute or stat resulting in a sort ordering 69 // change, changing the sort ordering rule. When getting a selected item, 70 // there is no guarantee that the item will still be selected after the 71 // operation. The client must be able to deal with these inaccuracies. 72 // Specifying an index/entry_ref that no longer exists will be handled well. 73 74 #if 0 75 doo Tracker get Suites of Poses of Window test 76 doo Tracker get Path of Poses of Window test 77 doo Tracker count Entry of Poses of Window test 78 doo Tracker get Entry of Poses of Window test 79 doo Tracker get Entry 2 of Poses of Window test 80 doo Tracker count Selection of Poses of Window test 81 doo Tracker get Selection of Poses of Window test 82 doo Tracker delete Entry 'test/6L6' of Poses of Window test 83 doo Tracker execute Entry 'test/6L6' of Poses of Window test 84 doo Tracker execute Entry 2 of Poses of Window test 85 doo Tracker set Selection of Poses of Window test to [0,2] 86 doo Tracker set Selection of Poses of Window test to 'test/KT55' 87 doo Tracker create Selection of Poses of Window test to 'test/EL34' 88 doo Tracker delete Selection 'test/EL34' of Poses of Window test 89 #endif 90 91 // ToDo: 92 // access list view column state 93 // access poses 94 // - pose location 95 // - pose text widgets 96 97 98 #if _SUPPORTS_FEATURE_SCRIPTING 99 100 const property_info kPosesPropertyList[] = { 101 { kPropertyPath, 102 { B_GET_PROPERTY }, 103 { B_DIRECT_SPECIFIER }, 104 "get Path of ... # returns the path of a Tracker window, " 105 "error if no path associated", 106 0, 107 { B_REF_TYPE }, 108 {}, 109 {} 110 }, 111 { kPropertyEntry, 112 { B_COUNT_PROPERTIES }, 113 { B_DIRECT_SPECIFIER }, 114 "count Entry of ... # count entries in a PoseView", 115 0, 116 { B_INT32_TYPE }, 117 {}, 118 {} 119 }, 120 { kPropertyEntry, 121 { B_DELETE_PROPERTY }, 122 { B_ENTRY_SPECIFIER, B_INDEX_SPECIFIER }, 123 "delete Entry {path|index} # deletes specified entries in a PoseView", 124 0, 125 {}, 126 {}, 127 {} 128 }, 129 { kPropertyEntry, 130 { B_GET_PROPERTY }, 131 { B_DIRECT_SPECIFIER, B_INDEX_SPECIFIER, kPreviousSpecifier, 132 kNextSpecifier }, 133 "get Entry [next|previous|index] # returns specified entries", 134 0, 135 { B_REF_TYPE }, 136 {}, 137 {} 138 }, 139 { kPropertyEntry, 140 { B_EXECUTE_PROPERTY }, 141 { B_ENTRY_SPECIFIER, B_INDEX_SPECIFIER }, 142 "execute Entry {path|index} # opens specified entries", 143 0, 144 { B_REF_TYPE }, 145 {}, 146 {} 147 }, 148 { kPropertySelection, 149 { B_GET_PROPERTY }, 150 { B_DIRECT_SPECIFIER, kPreviousSpecifier, kNextSpecifier }, 151 "get Selection [next|previous] # returns the selected entries", 152 0, 153 { B_REF_TYPE }, 154 {}, 155 {} 156 }, 157 { kPropertySelection, 158 { B_SET_PROPERTY }, 159 { B_DIRECT_SPECIFIER, kPreviousSpecifier, kNextSpecifier }, 160 "set Selection of ... to {next|previous|entry} # selects specified " 161 "entries", 162 0, 163 {}, 164 {}, 165 {} 166 }, 167 { kPropertySelection, 168 { B_COUNT_PROPERTIES }, 169 { B_DIRECT_SPECIFIER }, 170 "count Selection of ... # counts selected items", 171 0, 172 { B_INT32_TYPE }, 173 {}, 174 {} 175 }, 176 { kPropertySelection, 177 { B_CREATE_PROPERTY }, 178 { B_DIRECT_SPECIFIER }, 179 "create selection of ... to {entry|index} " 180 "# adds specified items to a selection in a PoseView", 181 0, 182 {}, 183 {}, 184 {} 185 }, 186 { kPropertySelection, 187 { B_DELETE_PROPERTY }, 188 { B_ENTRY_SPECIFIER, B_INDEX_SPECIFIER }, 189 "delete selection {path|index} of ... " 190 "# removes specified items from a selection in a PoseView", 191 0, 192 {}, 193 {}, 194 {} 195 }, 196 { NULL, 197 {}, 198 {}, 199 NULL, 0, 200 {}, 201 {}, 202 {} 203 } 204 }; 205 206 #endif 207 208 209 status_t 210 BPoseView::GetSupportedSuites(BMessage* _SCRIPTING_ONLY(data)) 211 { 212 #if _SUPPORTS_FEATURE_SCRIPTING 213 data->AddString("suites", kPosesSuites); 214 BPropertyInfo propertyInfo( 215 const_cast<property_info*>(kPosesPropertyList)); 216 data->AddFlat("messages", &propertyInfo); 217 218 return _inherited::GetSupportedSuites(data); 219 #else 220 return B_UNSUPPORTED; 221 #endif 222 } 223 224 225 bool 226 BPoseView::HandleScriptingMessage(BMessage* _SCRIPTING_ONLY(message)) 227 { 228 #if _SUPPORTS_FEATURE_SCRIPTING 229 if (message->what != B_GET_PROPERTY 230 && message->what != B_SET_PROPERTY 231 && message->what != B_CREATE_PROPERTY 232 && message->what != B_COUNT_PROPERTIES 233 && message->what != B_DELETE_PROPERTY 234 && message->what != B_EXECUTE_PROPERTY) 235 return false; 236 237 // dispatch scripting messages 238 BMessage reply(B_REPLY); 239 const char* property = 0; 240 bool handled = false; 241 242 int32 index = 0; 243 int32 form = 0; 244 BMessage specifier; 245 status_t result = message->GetCurrentSpecifier(&index, &specifier, 246 &form, &property); 247 248 if (result != B_OK || index == -1) 249 return false; 250 251 ASSERT(property); 252 253 switch (message->what) { 254 case B_CREATE_PROPERTY: 255 handled = CreateProperty(message, &specifier, form, property, 256 &reply); 257 break; 258 259 case B_GET_PROPERTY: 260 handled = GetProperty(&specifier, form, property, &reply); 261 break; 262 263 case B_SET_PROPERTY: 264 handled = SetProperty(message, &specifier, form, property, 265 &reply); 266 break; 267 268 case B_COUNT_PROPERTIES: 269 handled = CountProperty(&specifier, form, property, &reply); 270 break; 271 272 case B_DELETE_PROPERTY: 273 handled = DeleteProperty(&specifier, form, property, &reply); 274 break; 275 276 case B_EXECUTE_PROPERTY: 277 handled = ExecuteProperty(&specifier, form, property, &reply); 278 break; 279 } 280 281 if (handled) { 282 // done handling message, send a reply 283 message->SendReply(&reply); 284 } 285 286 return handled; 287 #else 288 return false; 289 #endif 290 } 291 292 293 bool 294 BPoseView::ExecuteProperty(BMessage* _SCRIPTING_ONLY(specifier), 295 int32 _SCRIPTING_ONLY(form), const char* _SCRIPTING_ONLY(property), 296 BMessage* _SCRIPTING_ONLY(reply)) 297 { 298 #if _SUPPORTS_FEATURE_SCRIPTING 299 status_t error = B_OK; 300 bool handled = false; 301 if (strcmp(property, kPropertyEntry) == 0) { 302 BMessage launchMessage(B_REFS_RECEIVED); 303 304 if (form == (int32)B_ENTRY_SPECIFIER) { 305 // move all poses specified by entry_ref to Trash 306 entry_ref ref; 307 for (int32 index = 0; specifier->FindRef("refs", index, &ref) 308 == B_OK; index++) 309 launchMessage.AddRef("refs", &ref); 310 } else if (form == (int32)B_INDEX_SPECIFIER) { 311 // move all poses specified by index to Trash 312 int32 specifyingIndex; 313 for (int32 index = 0; specifier->FindInt32("index", index, 314 &specifyingIndex) == B_OK; index++) { 315 BPose* pose = PoseAtIndex(specifyingIndex); 316 317 if (!pose) { 318 error = B_ENTRY_NOT_FOUND; 319 break; 320 } 321 322 launchMessage.AddRef("refs", pose->TargetModel()->EntryRef()); 323 } 324 } else 325 return false; 326 327 if (error == B_OK) { 328 // add a messenger to the launch message that will be used to 329 // dispatch scripting calls from apps to the PoseView 330 launchMessage.AddMessenger("TrackerViewToken", 331 BMessenger(this, 0, 0)); 332 if (fSelectionHandler) 333 fSelectionHandler->PostMessage(&launchMessage); 334 } 335 handled = true; 336 } 337 338 if (error != B_OK) 339 reply->AddInt32("error", error); 340 341 return handled; 342 #else 343 return false; 344 #endif 345 } 346 347 348 bool 349 BPoseView::CreateProperty(BMessage* _SCRIPTING_ONLY(specifier), BMessage*, 350 int32 _SCRIPTING_ONLY(form), const char* _SCRIPTING_ONLY(property), 351 BMessage* _SCRIPTING_ONLY(reply)) 352 { 353 #if _SUPPORTS_FEATURE_SCRIPTING 354 status_t error = B_OK; 355 bool handled = false; 356 if (strcmp(property, kPropertySelection) == 0) { 357 // creating on a selection expands the current selection 358 359 if (form != B_DIRECT_SPECIFIER) 360 // only support direct specifier 361 return false; 362 363 // items to add to a selection may be passed as refs or as indices 364 if (specifier->HasRef("data")) { 365 entry_ref ref; 366 // select poses specified by entries 367 for (int32 index = 0; specifier->FindRef("data", index, &ref) 368 == B_OK; index++) { 369 370 int32 poseIndex; 371 BPose* pose = FindPose(&ref, form, &poseIndex); 372 373 if (!pose) { 374 error = B_ENTRY_NOT_FOUND; 375 handled = true; 376 break; 377 } 378 379 AddPoseToSelection(pose, poseIndex); 380 } 381 handled = true; 382 } else { 383 // select poses specified by indices 384 int32 specifyingIndex; 385 for (int32 index = 0; specifier->FindInt32("data", index, 386 &specifyingIndex) == B_OK; index++) { 387 388 BPose* pose = PoseAtIndex(specifyingIndex); 389 if (!pose) { 390 error = B_BAD_INDEX; 391 handled = true; 392 break; 393 } 394 395 AddPoseToSelection(pose, specifyingIndex); 396 } 397 handled = true; 398 } 399 } 400 401 if (error != B_OK) 402 reply->AddInt32("error", error); 403 404 return handled; 405 #else 406 return false; 407 #endif 408 } 409 410 411 bool 412 BPoseView::DeleteProperty(BMessage* _SCRIPTING_ONLY(specifier), 413 int32 _SCRIPTING_ONLY(form), const char* _SCRIPTING_ONLY(property), 414 BMessage* _SCRIPTING_ONLY(reply)) 415 { 416 #if _SUPPORTS_FEATURE_SCRIPTING 417 status_t error = B_OK; 418 bool handled = false; 419 420 if (strcmp(property, kPropertySelection) == 0) { 421 // deleting on a selection is handled as removing a part of the 422 // selection not to be confused with deleting a selected item 423 424 if (form == (int32)B_ENTRY_SPECIFIER) { 425 entry_ref ref; 426 // select poses specified by entries 427 for (int32 index = 0; specifier->FindRef("refs", index, &ref) 428 == B_OK; index++) { 429 430 int32 poseIndex; 431 BPose* pose = FindPose(&ref, form, &poseIndex); 432 433 if (!pose) { 434 error = B_ENTRY_NOT_FOUND; 435 break; 436 } 437 438 RemovePoseFromSelection(pose); 439 } 440 handled = true; 441 442 } else if (form == B_INDEX_SPECIFIER) { 443 // move all poses specified by index to Trash 444 int32 specifyingIndex; 445 for (int32 index = 0; specifier->FindInt32("index", index, 446 &specifyingIndex) == B_OK; index++) { 447 BPose* pose = PoseAtIndex(specifyingIndex); 448 449 if (!pose) { 450 error = B_BAD_INDEX; 451 break; 452 } 453 454 RemovePoseFromSelection(pose); 455 } 456 handled = true; 457 } else 458 return false; 459 460 } else if (strcmp(property, kPropertyEntry) == 0) { 461 // deleting entries is handled by moving entries to trash 462 463 // build a list of entries, specified by the specifier 464 BObjectList<entry_ref>* entryList = new BObjectList<entry_ref>(); 465 // list will be deleted for us by the trashing thread 466 467 if (form == (int32)B_ENTRY_SPECIFIER) { 468 // move all poses specified by entry_ref to Trash 469 entry_ref ref; 470 for (int32 index = 0; specifier->FindRef("refs", index, &ref) 471 == B_OK; index++) 472 entryList->AddItem(new entry_ref(ref)); 473 474 } else if (form == (int32)B_INDEX_SPECIFIER) { 475 // move all poses specified by index to Trash 476 int32 specifyingIndex; 477 for (int32 index = 0; specifier->FindInt32("index", index, 478 &specifyingIndex) == B_OK; index++) { 479 BPose* pose = PoseAtIndex(specifyingIndex); 480 481 if (!pose) { 482 error = B_BAD_INDEX; 483 break; 484 } 485 486 entryList->AddItem( 487 new entry_ref(*pose->TargetModel()->EntryRef())); 488 } 489 } else 490 return false; 491 492 if (error == B_OK) { 493 TrackerSettings settings; 494 if (!settings.DontMoveFilesToTrash()) { 495 // move the list we build into trash, don't make the 496 // trashing task select the next item 497 MoveListToTrash(entryList, false, false); 498 } else 499 Delete(entryList, false, settings.AskBeforeDeleteFile()); 500 } 501 502 handled = true; 503 } 504 505 if (error != B_OK) 506 reply->AddInt32("error", error); 507 508 return handled; 509 #else 510 return false; 511 #endif 512 } 513 514 515 bool 516 BPoseView::CountProperty(BMessage*, int32, 517 const char* _SCRIPTING_ONLY(property), 518 BMessage* _SCRIPTING_ONLY(reply)) 519 { 520 #if _SUPPORTS_FEATURE_SCRIPTING 521 bool handled = false; 522 //PRINT(("BPoseView::CountProperty, %s\n", property)); 523 524 // just return the respecitve counts 525 if (strcmp(property, kPropertySelection) == 0) { 526 reply->AddInt32("result", fSelectionList->CountItems()); 527 handled = true; 528 } else if (strcmp(property, kPropertyEntry) == 0) { 529 reply->AddInt32("result", fPoseList->CountItems()); 530 handled = true; 531 } 532 return handled; 533 #else 534 return false; 535 #endif 536 } 537 538 539 bool 540 BPoseView::GetProperty(BMessage* _SCRIPTING_ONLY(specifier), 541 int32 _SCRIPTING_ONLY(form), const char* _SCRIPTING_ONLY(property), 542 BMessage* _SCRIPTING_ONLY(reply)) 543 { 544 #if _SUPPORTS_FEATURE_SCRIPTING 545 // PRINT(("GetProperty %s\n", property)); 546 bool handled = false; 547 status_t error = B_OK; 548 549 if (strcmp(property, kPropertyPath) == 0) { 550 if (form == B_DIRECT_SPECIFIER) { 551 handled = true; 552 if (!TargetModel()) 553 error = B_NOT_A_DIRECTORY; 554 else 555 reply->AddRef("result", TargetModel()->EntryRef()); 556 } 557 } else if (strcmp(property, kPropertySelection) == 0) { 558 int32 count = fSelectionList->CountItems(); 559 switch (form) { 560 case B_DIRECT_SPECIFIER: 561 // return entries of all poses in selection 562 for (int32 index = 0; index < count; index++) 563 reply->AddRef("result", fSelectionList->ItemAt(index)-> 564 TargetModel()->EntryRef()); 565 566 handled = true; 567 break; 568 569 case kPreviousSpecifier: 570 case kNextSpecifier: 571 { 572 // return entry and index of selected pose before or after 573 // specified pose 574 entry_ref ref; 575 if (specifier->FindRef("data", &ref) != B_OK) 576 break; 577 578 int32 poseIndex; 579 BPose* pose = FindPose(&ref, &poseIndex); 580 581 for (;;) { 582 if (form == (int32)kPreviousSpecifier) 583 pose = PoseAtIndex(--poseIndex); 584 else if (form == (int32)kNextSpecifier) 585 pose = PoseAtIndex(++poseIndex); 586 587 if (!pose) { 588 error = B_ENTRY_NOT_FOUND; 589 break; 590 } 591 592 if (pose->IsSelected()) { 593 reply->AddRef("result", 594 pose->TargetModel()->EntryRef()); 595 reply->AddInt32("index", IndexOfPose(pose)); 596 break; 597 } 598 } 599 600 handled = true; 601 break; 602 } 603 } 604 } else if (strcmp(property, kPropertyEntry) == 0) { 605 int32 count = fPoseList->CountItems(); 606 switch (form) { 607 case B_DIRECT_SPECIFIER: 608 { 609 // return all entries of all poses in PoseView 610 for (int32 index = 0; index < count; index++) { 611 reply->AddRef("result", 612 PoseAtIndex(index)->TargetModel()->EntryRef()); 613 } 614 615 handled = true; 616 break; 617 } 618 619 case B_INDEX_SPECIFIER: 620 { 621 // return entry at index 622 int32 index; 623 if (specifier->FindInt32("index", &index) != B_OK) 624 break; 625 626 if (!PoseAtIndex(index)) { 627 error = B_BAD_INDEX; 628 handled = true; 629 break; 630 } 631 reply->AddRef("result", 632 PoseAtIndex(index)->TargetModel()->EntryRef()); 633 634 handled = true; 635 break; 636 } 637 638 case kPreviousSpecifier: 639 case kNextSpecifier: 640 { 641 // return entry and index of pose before or after 642 // specified pose 643 entry_ref ref; 644 if (specifier->FindRef("data", &ref) != B_OK) 645 break; 646 647 int32 tmp; 648 BPose* pose = FindPose(&ref, form, &tmp); 649 650 if (!pose) { 651 error = B_ENTRY_NOT_FOUND; 652 handled = true; 653 break; 654 } 655 656 reply->AddRef("result", pose->TargetModel()->EntryRef()); 657 reply->AddInt32("index", IndexOfPose(pose)); 658 659 handled = true; 660 break; 661 } 662 } 663 } 664 665 if (error != B_OK) 666 reply->AddInt32("error", error); 667 668 return handled; 669 #else 670 return false; 671 #endif 672 } 673 674 675 bool 676 BPoseView::SetProperty(BMessage* _SCRIPTING_ONLY(message), BMessage*, 677 int32 _SCRIPTING_ONLY(form), const char* _SCRIPTING_ONLY(property), 678 BMessage* _SCRIPTING_ONLY(reply)) 679 { 680 #if _SUPPORTS_FEATURE_SCRIPTING 681 status_t error = B_OK; 682 bool handled = false; 683 684 if (strcmp(property, kPropertySelection) == 0) { 685 entry_ref ref; 686 687 switch (form) { 688 case B_DIRECT_SPECIFIER: 689 { 690 int32 selStart; 691 int32 selEnd; 692 if (message->FindInt32("data", 0, &selStart) == B_OK 693 && message->FindInt32("data", 1, &selEnd) == B_OK) { 694 695 if (selStart < 0 || selStart >= fPoseList->CountItems() 696 || selEnd < 0 || selEnd >= fPoseList->CountItems()) { 697 error = B_BAD_INDEX; 698 handled = true; 699 break; 700 } 701 702 SelectPoses(selStart, selEnd); 703 handled = true; 704 break; 705 } 706 } // fall thru 707 case kPreviousSpecifier: 708 case kNextSpecifier: 709 { 710 // PRINT(("SetProperty direct/previous/next %s\n", property)); 711 // select/unselect poses specified by entries 712 bool clearSelection = true; 713 for (int32 index = 0; message->FindRef("data", index, &ref) 714 == B_OK; index++) { 715 716 int32 poseIndex; 717 BPose* pose = FindPose(&ref, form, &poseIndex); 718 719 if (!pose) { 720 error = B_ENTRY_NOT_FOUND; 721 handled = true; 722 break; 723 } 724 725 if (clearSelection) { 726 // first selected item must call SelectPose so the 727 // selection gets cleared first 728 SelectPose(pose, poseIndex); 729 clearSelection = false; 730 } else 731 AddPoseToSelection(pose, poseIndex); 732 733 handled = true; 734 } 735 break; 736 } 737 } 738 } 739 740 if (error != B_OK) 741 reply->AddInt32("error", error); 742 743 return handled; 744 #else 745 return false; 746 #endif 747 } 748 749 750 BHandler* 751 BPoseView::ResolveSpecifier(BMessage* _SCRIPTING_ONLY(message), 752 int32 _SCRIPTING_ONLY(index), BMessage* _SCRIPTING_ONLY(specifier), 753 int32 _SCRIPTING_ONLY(form), const char* _SCRIPTING_ONLY(property)) 754 { 755 #if _SUPPORTS_FEATURE_SCRIPTING 756 BPropertyInfo propertyInfo( 757 const_cast<property_info*>(kPosesPropertyList)); 758 759 int32 result = propertyInfo.FindMatch(message, index, specifier, form, 760 property); 761 if (result < 0) { 762 //PRINT(("FindMatch result %d \n")); 763 return _inherited::ResolveSpecifier(message, index, specifier, 764 form, property); 765 } 766 767 return this; 768 #else 769 return NULL; 770 #endif 771 } 772 773 774 BPose* 775 BPoseView::FindPose(const entry_ref* _SCRIPTING_ONLY(ref), 776 int32 _SCRIPTING_ONLY(specifierForm), int32* _SCRIPTING_ONLY(index)) const 777 { 778 #if _SUPPORTS_FEATURE_SCRIPTING 779 // flavor of FindPose, used by previous/next specifiers 780 781 BPose* pose = FindPose(ref, index); 782 783 if (specifierForm == (int32)kPreviousSpecifier) 784 return PoseAtIndex(--*index); 785 else if (specifierForm == (int32)kNextSpecifier) 786 return PoseAtIndex(++*index); 787 else 788 return pose; 789 #else 790 return NULL; 791 #endif 792 } 793