Libreoffice Base - how to call a control event from a macro? - database

Question: I need to manually call an object listener event (e.g. key pressed) to trigger a function. I used to do it in Access but haven't found the documentation for it in LibreOffice Base.
Context: Having retired from software development 7 years ago, I am doing a favour for a friend by building a database in LibreOffice Base. Previously experienced in Access - but more with Oracle, PL/SQL, APEX, etc! I am struggling a little in getting it to do what I know can be done!

Here is the code I've tried so far.
Sub CauseKeyPressedEventToBeFired
oDoc = ThisComponent
oController = oDoc.getCurrentController()
oVC = oController.getViewCursor()
oForm = oDoc.getDrawpage().getForms().getByName("Form")
oTextBox = oForm.getByName("Text Box 1")
oControlView = oController.getControl(oTextBox)
oControlView.setFocus()
Dim oEvent As New com.sun.star.awt.KeyEvent
oEvent.Source = oControlView
oEvent.KeyCode = com.sun.star.awt.Key.A
oControlView.keyPressed(oEvent)
End Sub
However, it doesn't seem to work on my system (LibreOffice 6.4.3.2 on Windows). I also found this post, but that code doesn't seem to work for me either.
I searched for com.sun.star.awt.XToolkitRobot, but it's not in the API documentation, perhaps because the functionality is not fully supported. Presumably, it can be obtained from com.sun.star.awt.Toolkit.
For more help, post a question on ask.libreoffice.org. I'd suggest explaining why you want to do this, because there may be a different kind of solution. Ratslinger has a lot of experience solving various database problems, and he'll probably direct you toward a simpler solution that doesn't involve this kind of event hacking.
a function (i.e. a procedure that returns a value)
Yes, that is what a function is. But "an object listener event" implies, correctly I think, that we're talking about the method of an object instead. That's what LibreOffice event listeners are in Python or Java, although in Basic, they're a little strange, using the object name as some kind of magic to determine what they apply to. Anyway, that's getting off track, because your question isn't about listening for events, but rather about triggering them.
EDIT:
The following Python code works. The problem with my earlier attempts was that oEvent.KeyChar needs to be set, and that doesn't seem to work in Basic. I can't imagine why, unless I am ignoring some obvious mistake in the Basic code.
def causeKeyPressedEventToBeFired(oEvent=None):
oDoc = XSCRIPTCONTEXT.getDocument()
oController = oDoc.getCurrentController()
oForm = oDoc.getDrawPage().getForms().getByName("Form")
oTextBox = oForm.getByName("Text Box 1")
oControlView = oController.getControl(oTextBox)
oControlView.setFocus()
oEvent = uno.createUnoStruct("com.sun.star.awt.KeyEvent")
oEvent.Source = oControlView
from com.sun.star.awt.Key import A
oEvent.KeyCode = A
oEvent.KeyChar = "a" # works in Python but strangely not in Basic
simulate_KeyPress(oEvent)
def simulate_KeyPress(oKeyEvent):
oDoc = XSCRIPTCONTEXT.getDocument()
oWindow = oDoc.CurrentController.Frame.getContainerWindow()
oKeyEvent.Source = oWindow
oToolkit = oWindow.getToolkit()
oToolkit.keyPress(oKeyEvent)
oToolkit.keyRelease(oKeyEvent)
EDIT 2:
Finally, here is working Basic code. In the earlier attempt, the type was wrong.
Sub CauseKeyPressedEventToBeFired
oDoc = ThisComponent
oController = oDoc.getCurrentController()
oForm = oDoc.getDrawpage().getForms().getByName("Form")
oTextBox = oForm.getByName("Text Box 1")
oControlView = oController.getControl(oTextBox)
oControlView.setFocus()
Dim oEvent As New com.sun.star.awt.KeyEvent
oEvent.KeyCode = com.sun.star.awt.Key.A
oEvent.KeyChar = CByte(97)
simulate_KeyPress(oEvent)
End Sub
Sub simulate_KeyPress(oKeyEvent As com.sun.star.awt.KeyEvent)
oWindow = ThisComponent.CurrentController.Frame.getContainerWindow()
oKeyEvent.Source = oWindow
oToolkit = oWindow.getToolkit()
oToolkit.keyPress(oKeyEvent)
oToolkit.keyRelease(oKeyEvent)
End Sub

Related

Windows Form "Jumps" when clicked

This question is regarding a Windows form built in PowerShell using System.Windows.Forms - I intend to convert it to C# at some point, just hasn't happened yet. C# contextual answers welcomed.
So in order to make this tool appear more like an "app" verses another WPF thing, the control boxes were removed, along with the title. In doing so, we lose the ability to move the form. So I decided to write a nice little number to handle that, which you all may agree or disagree with. Anyhow, it works great on my workstation, laptop, and a remote session to a few random terminal servers. However, when testing with a user, the app experiences a "jump" when clicked on where this bit of code might be picking up on the mouse click. The form's icon still shows in the toolbar, but it's obvious that the form has gone way off screen, and cannot be pulled back to center. I am not 100% sure if it's the code, but I have a feeling. I cannot reproduce this on my machines. Please don't tell me how to get the form back on the screen, that is just a workaround. I appreciate any ideas.
$GLOBAL:ButtonDown = 0
$GLOBAL:FX = 0
$GLOBAL:MX = 0
$GLOBAL:FY = 0
$GLOBAL:MY = 0
$Form.Add_MouseUp({handler_Form_MouseUp})
function handler_Form_MouseUp{$GLOBAL:ButtonDown = 0}
$Form.Add_MouseDown({handler_Form_MouseDown})
function handler_Form_MouseDown{
$GLOBAL:FX = $Form.Location.X
$GLOBAL:MX = [System.Windows.Forms.Cursor]::Position.X
$GLOBAL:FY = $Form.Location.Y
$GLOBAL:MY = [System.Windows.Forms.Cursor]::Position.Y
$GLOBAL:ButtonDown = 1
}
$Form.Add_MouseMove({handler_Form_MouseMove})
function handler_Form_MouseMove{
if($GLOBAL:ButtonDown){
#write-host ("X:"+ ([System.Windows.Forms.Cursor]::Position.X) + " || Y:" + ([System.Windows.Forms.Cursor]::Position.Y))
$newX = $GLOBAL:FX + ([System.Windows.Forms.Cursor]::Position.X - $GLOBAL:MX)
$newY = $GLOBAL:FY + ([System.Windows.Forms.Cursor]::Position.Y - $GLOBAL:MY)
$Form.SetDesktopLocation($newX, $newY)
$GLOBAL:FX = $Form.Location.X
$GLOBAL:MX = [System.Windows.Forms.Cursor]::Position.X
$GLOBAL:FY = $Form.Location.Y
$GLOBAL:MY = [System.Windows.Forms.Cursor]::Position.Y
}
}

Obfuscating code in AutoIt3

Some1 know which obfuscator obfuscate variables like this?
$a3a83605e4a
And functions like this?
Func a2060102a0b($a0c9b315f62, $a199bf1090b = 0, $a58ab015626 = False)
If NOT IsDeclared("SSA2060102A0B") Then
Global $a40ab115d31 = a2a0000482b($os[3999]), $a4fab210961 = a2a0000482b($os[4000]), $a09ab311939 = a2a0000482b($os[4001]), $a25ab415f29 = a2a0000482b($os[4002]), $a53ab510350 = a2a0000482b($os[4003]), $a06ab61560c = a2a0000482b($os[4004]), $a57ab714857 = a2a0000482b($os[4005]), $a2dab81175c = a2a0000482b($os[4006]), $a0aab91562a = a2a0000482b($os[4007]), $a26aba10a40 = a2a0000482b($os[4008]), $a31abb11452 = a2a0000482b($os[4009]), $a19abc1013c = a2a0000482b($os[4010]), $a46abd1244d = a2a0000482b($os[4011]), $a61abe16335 = a2a0000482b($os[4012]), $a02abf1395e = a2a0000482b($os[4013])
Global $ssa2060102a0b = 1
EndIf
If $a199bf1090b = Number($a40ab115d31) Then $a199bf1090b = a05a0d0391a()
If #error Then Return SetError(Number($a4fab210961), #extended, Number($a09ab311939))
Local $a49f0d12024 = DllCall($a25ab415f29, $a53ab510350, $a06ab61560c, $a57ab714857, $a199bf1090b, $a2dab81175c, $a0c9b315f62, $a0aab91562a, $a58ab015626, $a26aba10a40, Number($a31abb11452))
If #error OR NOT $a49f0d12024[Number($a19abc1013c)] Then Return SetError(Number($a46abd1244d), #extended, Number($a61abe16335))
Return $a49f0d12024[Number($a02abf1395e)]
EndFunc
Until recently, the full version of the SciTE editor was shipped with an obfuscator, which with correct flags would just change variable names (though by default does much more). This has since changed to a "stripper" which performs a similar function, but for the primary purpose of making scripts smaller as opposed to difficult to read.
Au3Stripper is available for download here (scroll to the bottom of the page for the standalone version)
You may be able to find previous versions of the Obfuscator online (there is no official page for downloading old versions as far as I know).
There are some alternatives, such as one on the German forums here, though I haven't used it so can't say how good it is, or if the output matches what you are looking for.
It might be AutoIt Obfuscator from https://www.pelock.com/products/autoit-obfuscator
It seems it's using similar obfuscation techniques.

Visual Basic Referencing .Net Objects In An Array

I have a big list of objects in the Design view of Visual Basic 2010 that I need to change a bunch of properties for, so of course I tried using an array rather than taking 50-60 lines for a repetitive task. But there seems to be an issue referencing to the object and it seems to be just taking the information from it. I know that was a shitty explanation, but maybe you'll understand it when you see it.
Dim objectsToClear As Array = _
{lblDailyRoundTrip, lblDaysWorked, lblFillBoxes, lblMilesPerGallon, lblMonthlyInsurance, _
lblMonthlyMaintenance, lblMonthlyParking, tbDailyRoundTrip, tbDaysWorked, tbMilesPerGallon, _
tbMonthlyInsurance, tbMonthlyMaintenance, tbMonthlyParking}
For i = LBound(objectsToClear) To UBound(objectsToClear)
objectsToClear(i).Text = ""
objectsToClear(i).Visible = False
Next
Try this instead:
Dim objectsToClear As Array = { lblDailyRoundTrip,
lblDaysWorked,
lblFillBoxes,
lblMilesPerGallon,
lblMonthlyInsurance,
lblMonthlyMaintenance,
lblMonthlyParking,
tbDailyRoundTrip,
tbDaysWorked,
tbMilesPerGallon,
tbMonthlyInsurance,
tbMonthlyMaintenance,
tbMonthlyParking }
For Each item In objectsToClear
item.Text = String.Empty
item.Visible = False
Next item
P.S. - you REALLY should have Option Strict On, and you should have strongly typed your array.
Since you seem to be interested in changing only .Text and .Visible properties, then you can just find the control by name, like this:
Dim returnValue As Control()
returnValue = Me.Controls.Find(objectsToClear(i), True)
Note: The True argument is for whether or not to search all children, which it sounds like you want to do. Read Control.ControlCollection.Find Method documentation for more information.
Now that you have a collection of controls that match the name you specified, loop through the controls in that collection and set the property values, like this:
For Each c As Control In returnValue
c.Text = ""
c.Visible = False
Next

Silverlight replacement for BinaryReader.ReadDecimal

In Silverlight 4, BinaryReader doesn't seem to have any ReadDecimal() method.
Reflector shows that it's there but with internal visibility, rather than public.
Aside from using that one via dynamic trickery or Reflection, has anyone got a good workaround for getting it. Or is this all part of the plan?
Erica Aside: amusingly, Reflector also shows that there are 10 InternalsVisibleToAttributes in the Ag mscorlib (sadly none to mine :D), which I assume, at 512+ bytes a go gives plenty scope for optimization! I'm sure Bob is in there too :D
There is no direct replacement, but you can achieve the same result like this:
// write it, assume bw = BinaryWriter
var bits = decimal.GetBits(myDecimal);
bw.Write(bits[0]);
bw.Write(bits[1]);
bw.Write(bits[2]);
bw.Write(bits[3]);
// read it, assume br = BinaryReader
var bits = new int[4];
bits[0] = br.ReadInt32();
bits[1] = br.ReadInt32();
bits[2] = br.ReadInt32();
bits[3] = br.ReadInt32();
return new decimal(bits);

MS Access - open a form taking a field value from a previous form

I have a form in an MS Access database which lists all the landowners consulted with for a new electricity line. At the end of each row is a button which opens another form, showing the details of all consultation, offers made etc.
I am trying to use vb in MS Access to take the contactID and automatically put it in a field in the details form, so that landowner's consultation details will pop up automatically. I am not a vb programmer at all (I have a comp sci degree mostly in Java and I'm currently working as a GIS analyst but it's a small company so I've been asked to get an Access database working).
I want to say
[detailsForm]![contactID] = [landownerlist]![ID]
in a way that vb and access will be happy with. Then I can see if I'm on the right track and if it will actually work! What I have above does not actually work. It won't compile.
From Kaliana
If you wish to open a form to a new record and to set the ID there, you can use Openargs, an argument of Openform:
DoCmd.OpenForm "FormName",,,,acFormAdd,,Me.ID
The opened form would also need some code:
If Me.Openargs<>vbNullstring Then
Me.Id = Me.Openargs
End If
It is also possible to find:
Forms!LandownersList.Recordset.FindFirst "ID=" & Me.ID
or fill in a value:
Forms!LandownersList!Id = Me.ID
on the form being opened from the calling form.
You may want to look into the code that is behind these buttons. If you are using a docmd.openform you can set the 4th Setting to a where clause on openning the next form.
DoCmd.OpenForm "OpenFormName", acNormal, , "[contactID] = " _
& [detailsForm]![contactID] , acFormEdit, acWindowNormal
This assumes contact ID is numeric and doesn't require any quotes.
Using open args is the generally accepted solution, as alluded to by others. This just falls under the category of "For you edification":) One of the problems with using open args is that unless you are careful with your comments it's easy to forget what they were supposed to mean. Were you passing more than one? Which is which? How did I do it here? How did I do it there etc. For my own money, I standardized to this (below) so I can always pass more than one argument without fear, and when I review my code a year from now, I can still see what's what without a huge hassle:
Option Explicit
'Example use: DoCmd.OpenForm "Example", OpenArgs:="Some Filter|True"
Public Enum eForm1Args
eFilter = 0
eIsSpecial = 1
End Enum
Private m_strArgs() As String
Public Property Get Args(ByVal eForm1Args As eForm1Args) As String
Args = m_strArgs(eForm1Args)
End Property
Private Sub Form_Open(Cancel As Integer)
m_strArgs = Split(Nz(Me.OpenArgs, vbNullString), "|")
If LenB(Me.Args(eFilter)) Then Me.Filter = Me.Args(eFilter)
End Sub
Private Sub Command1_Click()
If LCase$(Me.Args(eIsSpecial)) = "true" Then
'Do something special
End If
End Sub
As previously posted OpenArgs is great for this. One trick I have learned is that it is easy to pass in multiple parameters if required as a delimited string (comma for example), the target form can then access these values using the Split() function thus:
StringArrayVariable()= Split(me.OpenArgs,",")
Me.textbox= StringArrayVariable(0)
Me.textbox1= StringArrayVariable(1)
etc.
This is air code so check out the helpfile for Split().
It is also possible to pass objects in OpenArgs as well, it requires some manual memory pointer manipulation and I don't have the code to hand but I'm sure a Google search will find some examples. This technique can cause some random crashes though. Be Warned!

Resources