Creating an object verb menu
Verbs are actions that a container can ask an OLE object to perform. The names of the verbs that an OLE object can execute are registered with the object in the system registry. All OLE objects have one verb designated as the primary verb, which in most cases is Edit. Other common verbs are Open, Show, Hide, and Play.
When an OLE object is activated in its container by double-clicking on the OleClient widget, it is the primary verb that is invoked on the OLE object. Therefore, if the Edit verb is the primary verb, on activation, the server opens for editing on the OLE object. Verbs can also be invoked programmatically through the doVerb: method of OleClient. The parameter to this method is the name of the verb to execute. For example, a contained OLE object can be activated for editing using anOleClient doVerb: 'Edit'.
The doVerb: method can also take as a parameter a constant representing the most common verbs that most OLE objects support. For example, the edit verb could also be invoked using anOleClient doVerb: XmVERBPRIMARY.
The standard parameter values for the OLE doVerb: include the following:
Open the OLE object for editing
Show the OLE object
Open the OLE object for editing in a separate window
Hide the OLE object
Activate the UI for the OLE object
Open the OLE object for editing in place
Close the OLE object and discard the undo state
Request the OLE object properties dialog
The OLE user interface guidelines suggest that a container provide access to an object's verbs from a cascade menu off its Edit menu. The container must dynamically change the contents of the cascade menu depending on which OleClient widget has the current focus. The guidelines also suggest that the label of the cascade menu change to reflect the name of the object that the verbs apply to.

A typical OLE object verb menu
To help build a dynamic verb menu, the OleClient class provides these instance methods:
Answers a String representing the type of contained OLE object
Answers a collection of strings that are the names of the verbs supported by the contained OLE object
These methods provide sufficient information to build the dynamic verb menus of a container application. As an example, suppose the Edit menu of an application is created as a simple pull-down menu using the following code:
createEditMenu: menuBar
"Private - Create and answer the Edit menu for the receiver."
| types |
types := OrderedCollection new.
editMenu := menuBar
createSimplePulldownMenu: 'edit'
argBlock: [:w |
buttons: #('Cut' 'Copy' 'Paste' 'Paste Special...'
'Delete Object' '' 'Insert Object...' 'Links...' 'Object');
buttonType: types;
buttonMnemonics: #();
postFromButton: 1].
addCallback: XmNsimpleCallback
receiver: [:w :clientData :callData |
| selectors |
selectors := #(menuEditCut menuEditCopy menuEditPaste
menuEditPasteSpecial menuEditDeleteObject menuEditInsertObject
menuEditLinks menuEditObject).
self perform: (selectors at: clientData + 1)]
selector: #value:value:value:
clientData: nil.
addCallback: XmNmapCallback
receiver: [:w :clientData :callData |
| widget buttons |
buttons := editMenu children.
widget := self shell focusWidget.
(buttons at: 1) sensitive: widget isOleClient. "Cut"
(buttons at: 9)
sensitive: self enableVerbs. "Object"]
selector: #value:value:value:
clientData: nil.
In this example, the last item on the menu is a cascade button that is used to attach the verb menu to. The verb menu must be disabled if no OleClient widget has focus. Hence, the XmNmapCallback callback calls the enableVerbs method to build the verb menu if appropriate. The enableVerbs method first checks for the existence of an OleClient with focus and, if it finds one, proceeds to build the verb menu:
"Private - Answer true if the selected embedded object's verbs
are to be enabled."
| widget |
widget := self shell focusWidget.
"Widget with focus is the selected item."
(widget isOleClient not or: widget isStaticEmbedding])
ifTrue: [
(editMenu children at: 9) labelString: 'Object'.
"An embedded or linked OLE object is selected, so add verb menu to edit menu."
self addObjectMenu: widget clientUserName
verbs: widget verbs.
The cascading verb menu is built in the addObject:verbs: method as follows:
addObjectMenu: objectType verbs: verbNames
"Private - Add an object menu for object with type name String
objectType containing the verb names in the verbNames Array."
| types labels verbCount objectMenu |
labels := OrderedCollection new: (verbCount := verbNames size) + 2.
types := OrderedCollection new: labels size.
1 to: verbCount do: [:i |
labels add: (verbNames at: i).
types add: XmPUSHBUTTON].
labels add: 'separator'; add: 'Convert'.
types add: XmSEPARATOR; add: XmPUSHBUTTON.
(editMenu children at: 9) labelString: (objectType, ' Object').
objectMenu := editMenu
createSimplePulldownMenu: 'object'
argBlock: [:w |
buttons: labels asArray;
buttonType: types asArray;
postFromButton: 8].
addCallback: XmNsimpleCallback
receiver: [:w :clientData :callData |
| widget |
widget := self shell focusWidget.
(widget isOleClient and: verbCount > 0])
ifTrue: [clientData >= verbCount
ifTrue: [self menuEditConvert]
ifFalse: [
widget doVerb: [(verbNames at: clientData + 1)]]]
selector: #value:value:value:
clientData: nil.
Notice in this example that one additional menu item, Convert, is attached to the bottom of the verb menu. This item provides access to the standard OLE Convert dialog, which allows you to change the display aspect of the OLE object from its content display to its icon display and conversely.

The standard OLE Convert Dialog
This dialog is easily invoked on an OleClient widget through its promptConvertObject method. For example:
"Private - Process the Edit menu Convert item."
| widget |
(widget := self shell focusWidget) isOleClient
ifFalse: [^self].
widget promptConvertObject == true
ifTrue: [changed := true]
The promptConvertObject method answers true if the display aspect of the OLE object changed. If it did, the OleClient widget's display was already refreshed to reflect the new aspect.
Last modified date: 12/22/2017