LibreOffice API: Given a FormControl. How to find the hosting shape?

Let pEvent be an event created by the usage of a FormControl belonging to a Form created as a member of the DrawPage of, say, a Spreadsheet.
The only way to get the associated (hosting) ControlShape I currently know is to analyze the pEvent.Source.AccessibleContext.AccessibleParent.ExtendedAttributes to get the “page-number”, then to access the sheet and its Drawpage, and to loop through the contained shapes. The hosting shape will know the control then, and I can stop browsing if a comparison ensures identity with the control itself.
Not really efficient, imo. And only for LibO Basic I know the needed function EqualUnoObjects(pObj1, pObj2).

Please teach me a better way. A “common” way preferred.

1 Like

The approach you suggest is quite correct.
You can similarly assign a unique name to Control.Model.Tag at the beginning, then find the ControlShape with this model name and at the end restore the Tag and, if necessary, the previous value of the IsModified property of the document.


BTW: Dou you actually understand for what reson this is complicated to the explained level?
Lots of ojects offer even larger lots of rarely needed properties for easy access. A SheetCell e.g. even is overloaded with text oriented services and the respective properties, and you can’t keep these very different fields of functionality separate. … Annoying to me. In this case the UI partly mixes up control properties and shape properties, but the API doesn’t even know the shape for the control?

1 Like

In my opinion, the fact that SheetCell can contain rich text is a huge advantage of Calc over Excel (in which, for example, you cannot make a hyperlink framed with plain text in a cell).
As for “API doesn’t even know the shape for the control” - for me this is not yet a fully explored area. After all, it’s always possible to ask the developers to create new APIs. :slightly_smiling_face:

Somehow reworked what I mostly already had:

Sub findDocAndHostingShapeForControlAndDoSomethingThen(pEvent)
On Local Error Goto fail
docAndShape = findDocAndHostingShapeForControl(pEvent)
REM Call myFullProgram(doAndShape)
End Sub

Function findDocAndHostingShapeForControl(pEvent)
Dim res()
findDocAndHostingShapeForControl = res
doc = pEvent.Source.Model.Parent.Parent.Parent
h = tryGetSheetForControl(doc, pEvent) 
REM The line above only works for Calc documents, Otherwise it returns the Null object.
REM Still don't know how to do it for drawings. Would need to search all the pages.
If IsNull(h) Then
  drPg = doc.DrawPage
  drPg = h.DrawPage
End If
shape = lookupDrawPageForShapeHostingControl(drPg, pEvent.Source.Model)
findDocAndHostingShapeForControl = Array(doc, shape)
End Function

Function lookupDrawPageForShapeHostingControl(pDrawPg, pModel) As Object
On Local Error Goto fail
u = pDrawPg.Count - 1
For j = 0 To u
  j_sh = pDrawPg(j)
  If j_sh.supportsService("") Then
    j_ctrl = j_sh.Control
    If EqualUnoObjects(j_ctrl, pModel) Then Exit For
  End If
Next j
If j<=u Then lookupDrawPageForShapeHostingControl = j_sh
End Function

Function tryGetSheetForControl(pDoc, pEvent) As Object
On Local Error Goto fail
extAttribs   = pEvent.Source.Peer.AccessibleContext.AccessibleParent.ExtendedAttributes
ctrlSheetName= Split(Split(extAttribs, ";")(0), ":")(1)
theCtrlSheet = pDoc.Sheets.GetByName(ctrlSheetName)
tryGetSheetForControl = theCtrlSheet
End Function   

(I won’t actually need this often, but I did not want to have pieces all around another time.
The given solution is tested with Wiriter documents and with Calc documents. For me the Calc case is more important.)

1 Like