| 454 | |
| 455 | |
| 456 | ResultType UserMenu::AddItem(LPTSTR aName, UINT aMenuID, IObject *aCallback, UserMenu *aSubmenu, LPTSTR aOptions |
| 457 | , UserMenuItem **aInsertAt) |
| 458 | // Caller must have already ensured that aName does not yet exist as a user-defined menu item |
| 459 | // in this->mMenu. |
| 460 | { |
| 461 | size_t length = _tcslen(aName); |
| 462 | if (length > MAX_MENU_NAME_LENGTH) |
| 463 | return g_script.RuntimeError(_T("Menu item name too long."), aName); |
| 464 | // After mem is allocated, the object takes charge of its later deletion: |
| 465 | LPTSTR name_dynamic; |
| 466 | if (length) |
| 467 | { |
| 468 | if ( !(name_dynamic = tmalloc(length + 1)) ) // +1 for terminator. |
| 469 | return MemoryError(); |
| 470 | _tcscpy(name_dynamic, aName); |
| 471 | } |
| 472 | else |
| 473 | name_dynamic = Var::sEmptyString; // So that it can be detected as a non-allocated empty string. |
| 474 | UserMenuItem *menu_item = new UserMenuItem(name_dynamic, length + 1, aMenuID, aCallback, aSubmenu, this); |
| 475 | if (!menu_item) // Should also be very rare. |
| 476 | { |
| 477 | if (name_dynamic != Var::sEmptyString) |
| 478 | free(name_dynamic); |
| 479 | return MemoryError(); |
| 480 | } |
| 481 | if (*aOptions && !UpdateOptions(menu_item, aOptions)) |
| 482 | { |
| 483 | // Invalid options; an error message was displayed. |
| 484 | delete menu_item; |
| 485 | return FAIL; |
| 486 | } |
| 487 | if (mMenu) |
| 488 | { |
| 489 | InternalAppendMenu(menu_item, aInsertAt ? *aInsertAt : NULL); |
| 490 | UPDATE_GUI_MENU_BARS(mMenuType, mMenu) |
| 491 | } |
| 492 | if (aInsertAt) |
| 493 | { |
| 494 | // Caller has passed a pointer to the variable in the linked list which should |
| 495 | // hold this new item; either &mFirstMenuItem or &previous_item->mNextMenuItem. |
| 496 | menu_item->mNextMenuItem = *aInsertAt; |
| 497 | // This must be done after the above: |
| 498 | *aInsertAt = menu_item; |
| 499 | } |
| 500 | else |
| 501 | { |
| 502 | // Append the item. |
| 503 | if (!mFirstMenuItem) |
| 504 | mFirstMenuItem = menu_item; |
| 505 | else |
| 506 | mLastMenuItem->mNextMenuItem = menu_item; |
| 507 | // This must be done after the above: |
| 508 | mLastMenuItem = menu_item; |
| 509 | } |
| 510 | ++mMenuItemCount; // Only after memory has been successfully allocated. |
| 511 | if (_tcschr(aName, '\t')) // v1.1.04: The new item has a keyboard accelerator. |
| 512 | UpdateAccelerators(); |
| 513 | return OK; |
nothing calls this directly
no test coverage detected