Nested UNO structs and properties of Objects that are structs behave in confusing ways. Consider: Sub TMP0() Dim b0 as new "com.sun.star.table.TableBorder" MsgBox b0.HorizontalLine.OuterLineWidth b0.HorizontalLine.OuterLineWidth = 9 MsgBox b0.HorizontalLine.OuterLineWidth End Sub Expected result: 0, then 9. Actual result: 0, then 0. The value change is *silently* ignored. The way to achieve changing the value is: Sub TMP1() Dim b0 as new "com.sun.star.table.TableBorder", l as new "com.sun.star.table.BorderLine" MsgBox b0.HorizontalLine.OuterLineWidth l = b0.HorizontalLine l.OuterLineWidth = 9 b0.HorizontalLine = l MsgBox b0.HorizontalLine.OuterLineWidth End Sub My guess is that in the statement "b0.HorizontalLine.OuterLineWidth = 9", the sub-expression "b0.HorizontalLine" returns a *temporary* fresh *copy* of the sub-struct, and that this temporary copy is modified instead of the substructure of b0. Now, consider this code which is supposed to change the borders of the table named "someTbl" in document "TST.odt": Sub TMP2() Dim docs as Object, doc as object docs = StarDesktop.Components.createEnumeration() Do While docs.hasMoreElements() doc = docs.nextElement() If doc.title = "TST.odt" Then dim tbl as object tbl = doc.getTextTables().getByName("someTbl") Dim border As new "com.sun.star.table.TableBorder", ligne As new "com.sun.star.table.BorderLine" ligne.OuterLineWidth = 1 border.HorizontalLine = ligne tbl.TableBorder = border MsgBox border.HorizontalLine.OuterLineWidth MsgBox tbl.TableBorder.HorizontalLine.OuterLineWidth End If Loop End Sub Again, the change is silently ignored! I don't really have an idea why. By contrast, this version works: Sub TMP2() Dim docs as Object, doc as object docs = StarDesktop.Components.createEnumeration() Do While docs.hasMoreElements() doc = docs.nextElement() If doc.title = "TST.odt" Then dim tbl as object tbl = doc.getTextTables().getByName("someTbl") Dim border As Object, ligne As new "com.sun.star.table.BorderLine" border = tbl.TableBorder ligne.OuterLineWidth = 1 border.HorizontalLine = ligne tbl.TableBorder = border End If Loop End Sub Also the following fails: Sub TMP3() Dim docs as Object, doc as object docs = StarDesktop.Components.createEnumeration() Do While docs.hasMoreElements() doc = docs.nextElement() If doc.title = "TST.odt" Then dim tbl as object tbl = doc.getTextTables().getByName("someTbl") Dim border As new "com.sun.star.table.TableBorder" ' the following assignment fails; error message "Object Required" border = tbl.TableBorder End If Loop End Sub Why can't "border", having the *right* struct type be assigned (by copy, "obviously") the value of tbl.TableBorder. Especially considering this does work: Sub TMP4() Dim docs as Object, doc as object docs = StarDesktop.Components.createEnumeration() Do While docs.hasMoreElements() doc = docs.nextElement() If doc.title = "Untitled 2" Then dim tbl as object tbl = doc.getTextTables().getByName("someTbl") Dim b0 as Object, border As new "com.sun.star.table.TableBorder" b0 = tbl.TableBorder border = b0 End If Loop End Sub
Reconfirmed with LibreOffice 3.5.0. Seems to be a quite old bug, I get it with OpenOffice.org 3.2, too.
->Sub TMP0() your suspicion is correct, UNO structures are value based and even for embedded structures it seems BASIC treats them the same way ->Sub TMP2() I strongly believe that it is writer that is playing tricks here and not Basic, in your working version you do border = tbl.TableBorder before modifying border.HorizontalLine, the real difference between your previous version and this one is that all the other members of border ( e.g. TopLine,IsTopLineValid,BottomLine,IsBottomLineValid ,LeftLine,IsLeftLineValid etc. ) so you are sending quite a different structure to the writer table. I would be 99% sure what you think you are sending in the previous example is really what is sent but just writer doesn't like it or it doesn't do what you expect. ->Sub TMP3() this one sounds like a real bug, looking at where it fails in basic it seems that the Variable type for TableBorder seems to marked as empty it should be Object, at a wild guess this is probably because although TableBorder has been evaluated it actually hasn't already called the associated uno method ( there is a lazy invoke type thing that basic does ) so it actually doesn't know what the real type is yet.
(In reply to comment #2) what I meant to say was ( except I didn't finish the sentence ) " before modifying border.HorizontalLine, the real difference between your previous version and this one is that all the other members of border ( e.g. TopLine,IsTopLineValid,BottomLine,IsBottomLineValid ,LeftLine,IsLeftLineValid etc. ) are populated with valid values from tbl.TableBorder" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
so tbl = doc.getTextTables().getByIndex(0) Dim border As new com.sun.star.table.TableBorder border = tbl.TableBorder as we know fails but the following ( which you would think the same thing ) CellRange = Doc.CurrentController.ActiveSheet.getCellRangeByName("c5") dim oBorder as new com.sun.star.table.BorderLine2 oBorder = CellRange.bottomBorder works perfectly, eventually I found where it goes wrong, it's all down to how the 'Property' is defined. In the case of TableBorder it is defined as PropertyAttribute::MAYBEVOID and because of that the type is set to variant/empty and then we fail when we try to check the class of border vs tbl.TableBorder. I will put yet another horrible hack into basic to allow the 'real' type of the property to be accessed
Noel Power committed a patch related to this issue. It has been pushed to "master": http://cgit.freedesktop.org/libreoffice/core/commit/?id=7dafa7a3b14441c6a27ab051db01f53e2c434f0a fix error comparing a struct vs an uno prop containing a struct fdo#42819
Marking as fixed. If there is something I missed perhaps a new bug might be better, there are quite some examples in here already and it could perhaps get confusing. For fixed I mean the 'Object required" behaviour is fixed which is afaics the only real bug here ( but I could be wrong )