Bug 42819 - [BASIC] nested UNO structs and UNO object properties of type "a uno struct" confusing
Summary: [BASIC] nested UNO structs and UNO object properties of type "a uno struct" c...
Status: RESOLVED FIXED
Alias: None
Product: LibreOffice
Classification: Unclassified
Component: BASIC (show other bugs)
Version:
(earliest affected)
3.4.3 release
Hardware: All All
: medium normal
Assignee: Noel Power
URL:
Whiteboard: target:3.6.0
Keywords:
Depends on:
Blocks: 47263
  Show dependency treegraph
 
Reported: 2011-11-11 06:51 UTC by Lionel Elie Mamane
Modified: 2012-03-13 00:07 UTC (History)
0 users

See Also:
Crash report or crash signature:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Lionel Elie Mamane 2011-11-11 06:51:27 UTC
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
Comment 1 Lionel Elie Mamane 2012-02-20 08:31:14 UTC
Reconfirmed with LibreOffice 3.5.0.

Seems to be a quite old bug, I get it with OpenOffice.org 3.2, too.
Comment 2 Noel Power 2012-03-09 06:59:35 UTC
->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.
Comment 3 Noel Power 2012-03-09 07:42:55 UTC
(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"
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Comment 4 Noel Power 2012-03-09 09:55:11 UTC
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
Comment 5 Not Assigned 2012-03-09 10:51:27 UTC
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
Comment 6 Noel Power 2012-03-09 10:54:21 UTC
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 )