[Base] Call MRI on forms or form controls from form document

Shared Libraries
Forum rules
For sharing working examples of macros / scripts. These can be in any script language supported by OpenOffice.org [Basic, Python, Netbean] or as source code files in Java or C# even - but requires the actual source code listing. This section is not for asking questions about writing your own macros.
Post Reply
Arineckaig
Volunteer
Posts: 828
Joined: Fri Nov 30, 2007 10:58 am
Location: Scotland

[Base] Call MRI on forms or form controls from form document

Post by Arineckaig »

I have been asked to post this code which some people have found helpful.

Hanya's MRI extension is an invaluable tool as an UNO object browser that will display properties, methods, interfaces and services relevant to any UNO object passed to it. It can readily be called by inserting a line into a macro. Often, however, I found I had a need to call MRI directly from a form document to check the properties, methods, interfaces and services applicable to a particular form or form control in that document.

To this end, and with essential help from Hanya, I have been using a routine that can be called whether the form document is in 'edit' or in 'direct' mode to display a form control tree similar to that used by the 'form navigator'. Double clicking the name of any form or form control shown in the list automatically runs MRI on the 'model' of that object and on its 'view' if the object has one. Unless the 'Auto close' box is checked the tree control remains open so that MRI can be run on other objects listed therein.

I store the module as a separate library under 'My Macros' and call its 'Main' routine from an icon added to the form document toolbar.

You use it at your own risk, but hopefully it should cause no damage as it only displays on the screen a tree control and one or more MRI results. Some routines at the end seem to be empty, but they must be included to prevent errors arising from the use of mouse and button event listeners. Please PM me if you find errors or have problems.

--------------------------------------------------------------
Edit 26 March 2011: Updated the code to include display of MRI scan of the 'View' of controls contained within a Grid control. Access to these View is only obtained through the View of the Grid Control and then using .GetByIndex to reach the View of the contained control, but never if the containing form document is in edit mode
--------------------------------------------------------------
Edit 26 Sep 2011: I have prepared a first draft of a User Guide for this macro that can be downloaded from https://www.dropbox.com/pri/get/Public/ ... c2nOMS5ORA.
--------------------------------------------------------------
Edits 11 Oct 2011, 30 June & 3 Jul 2012: Update code to access 'View' of columns in a Grid Control unless form document is in Edit Mode.

Code: Select all

REM  *****  BASIC  *****

    REM Control Tree Code
    REM  *****  BASIC  *****
    REM  I owe a debt of gratitude to Hanya for the Tree Control code as well as for the MRI extension.
    REM  All the remaining errors and bugs, however, are entirely my responsibility.
    REM  The Main macro can be run from a Form Document open (in either edit or run mode).       
    REM  Best called from an icon added to the standard toolbar saved in the OOoBase:Form design
    REM  It displays a dialog similar to that of the Form Navigator. Double clicking any control on the
    REM     list will run MRI on that control's model and where available on its view. A single click will
    REM     select a control from the list and MRI can then be run by selecting the MRI button.
    REM  Unless the auto  close check box has been selected, the dialog and Tree Control will remain
    REM      open to permit MRI to be run on further controls.
    REM  *******************************************************                               

    Dim oDoc As Object
    Dim oDocCtrl As Object
    Dim oForms As Object
    Dim oDialog As Object

    Sub Main
      oDoc = ThisComponent
      oDocCtrl=oDoc.GetCurrentController()
      If oDoc.supportsService("com.sun.star.text.TextDocument") Then
       oForms = oDoc.getDrawPage().getForms()
      ElseIf oDoc.supportsService("com.sun.star.sheet.SpreadsheetDocument") Then
       ' Spreadsheet needs problem about active sheet changing
       oForms = oDoc.getCurrentController().getActiveSheet().getDrawPage().getForms()
      Else MsgBox("This is neither a Writer nor a Calc document - Macro will abort",0) : Exit Sub
      End If
     
      ' create dialog
      oDialog = CreateUnoService("com.sun.star.awt.UnoControlDialog")
      oDialogModel = CreateUnoService("com.sun.star.awt.UnoControlDialogModel")
      oDialogModel.setPropertyValues( _
        Array("Height", "PositionX", "PositionY", "Width","Title"), _
        Array(200, 50, 50, 130, "Double Click to run MRI") )
      oDialog.setModel(oDialogModel)
     
      ' AutoClose check box
      oCheckModel = oDialogModel.createInstance("com.sun.star.awt.UnoControlCheckBoxModel")
      oCheckModel.setPropertyValues(_
        Array("Height", "Label", "PositionX", "PositionY", "State", "Width"), _
        Array(13, "Auto Close", 1, 187, 1, 40))
      oDialogModel.insertByName("AutoClose", oCheckModel)
     
      ' Close Button
      oCloseBtnModel = oDialogModel.createInstance("com.sun.star.awt.UnoControlButtonModel")
      oCloseBtnModel.setPropertyValues(_
        Array("Height", "Label", "PositionX", "PositionY", "PushButtonType", "Width"), _
        Array(13, "~Close", 94, 187, com.sun.star.awt.PushButtonType.CANCEL, 35))
      oDialogModel.insertByName("CloseBtn", oCloseBtnModel)
     
      ' MRI Button
      oMRIBtnModel = oDialogModel.createInstance("com.sun.star.awt.UnoControlButtonModel")
      oMRIBtnModel.setPropertyValues(_
        Array("Height", "Label", "PositionX", "PositionY", "PushButtonType", "Width"), _
        Array(13, "~MRI", 58, 187, com.sun.star.awt.PushButtonType.STANDARD, 35))
      oDialogModel.insertByName("MRIBtn", oMRIBtnModel)
     
      ' create tree control
      oTreeModel = oDialogModel.createInstance("com.sun.star.awt.tree.TreeControlModel")
      oTreeModel.setPropertyValues( _
        Array("Height", "PositionX", "PositionY", "SelectionType", "ShowsRootHandles", "Width"), _
        Array(186, 1, 1, com.sun.star.view.SelectionType.SINGLE, False, 128) )
      oDialogModel.insertByName("Tree", oTreeModel)
      oTree = oDialog.getControl("Tree")
     
      oTreeDataModel = CreateUnoService("com.sun.star.awt.tree.MutableTreeDataModel")

    ' make new tree model structure
      oTreeDataModel = CreateUnoService( _
        "com.sun.star.awt.tree.MutableTreeDataModel")
      ' top node
      oRootNode = oTreeDataModel.createNode("Forms", true)
      oRootNode.setCollapsedGraphicURL("private:graphicrepository/res/sx18013.png")
      oRootNode.setExpandedGraphicURL("private:graphicrepository/res/sx18013.png")
     
      ' set data to the root
      oTreeDataModel.setRoot(oRootNode)
      oTreeModel.DataModel = oTreeDataModel
     
      AddChildren(oForms, oTreeDataModel, oRootNode)
      oDialog.setVisible(True)
     
      oButtonListener = CreateUnoListener("ButtonPush_", "com.sun.star.awt.XActionListener")
      oMRIBtn = oDialog.getControl("MRIBtn").addActionListener(oButtonListener)
     
      oTree.expandNode(oRootNode) ' expand after dialog visible
      ExpandAllNodes(oTree, oRootNode)
     
      oMouseListener = CreateUnoListener("Mouse_", "com.sun.star.awt.XMouseListener")
      oTree.addMouseListener(oMouseListener)
     
      oDialog.execute()
      oTree.removeMouseListener(oMouseListener)
      CloseDialog()
    End Sub

    Sub CloseDialog()
      If oDialog.getControl("AutoClose").State = 1 Then
        oDialog.endExecute()
      Endif
    End Sub


    Function GetFormControl(oForms As Object, oNode As Object) As Object
      Dim oControl As Object
      Dim sNames() As String
      While NOT IsNull(oNode)
       n = UBound(sNames) +1
       ReDim Preserve sNames(n)
       sNames(n) = CStr(oNode.getDisplayValue())
       oNode = oNode.getParent()
      WEND
      ' find control
      oControl = oForms
      For i = UBound(sNames) -1 to 0 step -1
       oControl = oControl.getByName(sNames(i))
      Next
      GetFormControl = oControl
    End Function

    Sub SelectControl(oForms As Object, oNode As Object) As Object
      oControl = GetFormControl(oForms, oNode)
      If IsNull(oControl) Then Exit Sub
      oDoc.getCurrentController().select(oControl)
    End Sub

 Sub OpenWithMRI(oForms As Object, oControl As Object)
      Globalscope.BasicLibraries.loadLibrary("MRILib")
      oControl = GetFormControl(oForms, oControl)
      If IsNull(oControl) Then Exit Sub
      MRILib.Mri(oControl)
    REM Routine to get view of controls within Grid control
      if oControl.Parent.SupportsService("com.sun.star.form.component.GridControl") _
      	 THEN GetView(oControl) : Exit Sub   
    REM Views not available for Hidden Controls, Forms or Sub-Forms
      If oControl.SupportsService("com.sun.star.form.component.Form") OR _
      	 oControl.SupportsService("com.sun.star.form.Forms") OR _
         oControl.SupportsService("com.sun.star.form.component.HiddenControl") then Exit Sub               
    REM Document's Controller and Form Control's Model gives Form Control's View
    oView = oDocCtrl.GetControl(oControl)                   
    If NOT ISNULL(oView) then MRI oView                       
    End Sub

    Sub GetView(oControl)   REM Required for controls within a Grid/Table control
      IF oForms.Parent.CurrentController.isFormDesignMode() THEN Exit Sub 	REM Abort if Edit Mode
      oGridView =  oDocCtrl.GetControl(oControl.Parent).View
      For i = 0 to oGridView.Count-1
          If oGridView.GetByIndex(i).Model.Name = oControl.Name THEN
             MRI oGridView.GetByIndex(i)      REM MRI View of control in grid
          End if
       Next
    End Sub
    Sub Mouse_mousePressed(oEv As com.sun.star.awt.MouseEvent)
      If oEv.Buttons = com.sun.star.awt.MouseButton.RIGHT Then
        oTree = oEv.Source.getContext().getControl("Tree")
        oNearNode = oTree.getClosestNodeForLocation(oEv.X,oEv.Y)
        If IsNull(oNearNode) Then Exit Sub
       
        aRect = CreateUnoStruct("com.sun.star.awt.Rectangle")
        aRect.X = oEv.X + oTree.PosSize.X
        aRect.Y = oEv.Y + oTree.PosSize.Y
       
        oPopup = CreateUnoService("stardiv.vcl.PopupMenu")'"com.sun.star.awt.PopupMenu")
       
        oPopup.insertItem(1, "Select", 0, 0)
        oPopup.insertItem(2, "MRI", 0, 1)
        oPopup.setCommand(1, "select")
        oPopup.setCommand(2, "mri")
       
        n = oPopup.execute(oTree.getContext().getPeer(), aRect, _
        com.sun.star.awt.PopupMenuDirection.EXECUTE_DEFAULT)
        If n > 0 Then
          sCommand = oPopup.getCommand(n)
          Select Case sCommand
          Case "select"
            SelectControl(oForms, oNearNode)
          Case "mri"
            OpenWithMRI(oForms, oNearNode)
          End Select
          CloseDialog()
        End If
      End If
    End Sub


    Sub Mouse_mouseReleased(oEv)
      If oEv.Buttons = com.sun.star.awt.MouseButton.LEFT and oEv.ClickCount = 2 Then
        oTree = oEv.Source.getContext().getControl("Tree")
        oNearNode = oTree.getClosestNodeForLocation(oEv.X,oEv.Y)
        If IsNull(oNearNode) Then Exit Sub
        OpenWithMRI(oForms, oNearNode)
        CloseDialog
      End If
    End Sub

    Sub ButtonPush_actionPerformed(oEv As com.sun.star.awt.ActionEvent)
      ' get selected item
      Dim oSelected() As Object
      oTree = oEv.Source.getContext().getControl("Tree")
      oSelected = oTree.getSelection()
      If IsArray(oSelected) Then
        Exit Sub
      Else
        OpenWithMRI(oForms, oSelected(0))
        CloseDialog
      End If
    End Sub


    Sub AddChildren( oContainer As Object, oDataModel As Object, oParent As Object )
      For i = 0 To oContainer.getCount() - 1 step 1
        oModel = oContainer.getByIndex(i)
        sName = oModel.getName()
        sImageURL = GetImageURL(oModel.getServiceName())
       
        If HasUnoInterfaces(oModel, _
           "com.sun.star.container.XContainer") Then
          oChild = oDataModel.createNode(sName, true)
          AddChildren(oContainer.getByName(sName), oDataModel, oChild)
        Else
          oChild = oDataModel.createNode(sName, false)
        End If

        oChild.setExpandedGraphicURL(sImageURL)
        oChild.setCollapsedGraphicURL(sImageURL)
        oParent.appendChild(oChild)
      Next
    End Sub

    Sub ExpandAllNodes(oTree As Object, oParent)
      For i = 0 To oParent.getChildCount() - 1 step 1
       oChild = oParent.getChildAt(i)
       oTree.expandNode(oChild)
       If oChild.getChildCount() > 0 Then
         ExpandAllNodes(oTree, oChild)
       End If
      Next
    End Sub

    Function GetImageURL(sServiceName As String) As String
      Dim sName As String
      sControlService = Mid(sServiceName, 28) 'stardiv.one.form.component.Form
     
      sServices = Array(_
       "CheckBox", "ComboBox", "CommandButton", _
       "CurrencyField", "DateField", "Edit", "FileControl", _
       "FixedText", "Form", "FormattedField", _
       "Grid", "GroupBox", "HiddenControl", _
       "ImageButton", "ImageControl", "ListBox", _
       "NumericField", "PatternField", "RadioButton", _
       "TextField", "TimeField", _
       ".NavigationToolBar", ".SpinButton", ".ScrollBar")

      sNames = Array(_
       "sx10596", "sx10601", "sx10594", _
       "sx10707", "sx10704", "sx10599", "sx10605", _
       "sx10597", "sx10593", "sx10728", _
       "sx10603", "sx10598", "sx18022", _
       "sx10604", "sx10710", "sx10600", _
       "sx10706", "sx10708", "sx10595", _
       "sx10599", "sx10705", _
       "sx10607", "sx10769", "sx10768")
     
      For i = 0 To UBound(sServices) step 1
        If sServices(i) = sControlService Then
          sName = sNames(i)
          Exit For
        End If
      Next
      GetImageURL = "private:graphicrepository/res/" & sName & ".png"
    End Function

    Sub Mouse_mouseEntered(ev)
    End Sub
    Sub Mouse_mouseExited(ev)
    End Sub
    Sub Mouse_disposing(ev)
    End Sub

    Sub ButtonPush_dispose(oEv)
    End Sub
Last edited by Arineckaig on Tue Apr 04, 2017 9:41 pm, edited 13 times in total.
User avatar
Villeroy
Volunteer
Posts: 31269
Joined: Mon Oct 08, 2007 1:35 am
Location: Germany

Re: Call MRI on forms or form controls direct from form docu

Post by Villeroy »

Whenever I use some macros with Base forms, I never walk from the top of the hierarchy (active document>forms>form>getByName...). I prefer an entirely event driven style.
I use to bind the event I'm interested in to the Basic wrapper MRI.Module1.mri which passes the event struct with the source object and possibly some additional information. The initial object is the event struct, property "Source" is the calling object (form or form control) and getParent takes me one level higher in the object hierarchy.
This way I get 90% of the event driven code directly recorded by MRI.
Please, edit this topic's initial post and add "[Solved]" to the subject line if your problem has been solved.
Ubuntu 18.04 with LibreOffice 6.0, latest OpenOffice and LibreOffice
Arineckaig
Volunteer
Posts: 828
Joined: Fri Nov 30, 2007 10:58 am
Location: Scotland

Re: Call MRI on forms or form controls direct from form docu

Post by Arineckaig »

Villeroy, many thanks for your contribution - instructive and imaginative as ever. I suspect that many of us have developed shortcuts to uncover the undocumented potentials within MRI. If this thread merely brings some of them into the light of day it will hopefully have served its purpose.
When this issue has been resolved, it would help other users of the forum if you add the word - [Solved] - to the Subject line of your 1st post (edit button top right).
AOOo 4.1.5 & LO 6 on MS Windows 10 MySQL and HSQLDB
Arineckaig
Volunteer
Posts: 828
Joined: Fri Nov 30, 2007 10:58 am
Location: Scotland

Re: [Base]Call MRI on forms or form controls from form docum

Post by Arineckaig »

I have prepared and attached a meaningless Base file to provide a demonstration of the MRI tree control. It requires the MRI extension to have been added and the demonstration will not work unless the “MRILib” macros have already been stored in “My Macros and Dialogs”. A brief 'explanation' form document is included in the demonstration file. If, however, regular use is to be made of the macro it should be stored and used as described in the Tutorial mentioned in my first post above, that can still be downloaded from http://db.tt/AvMnUCAf..https://www.dropbox.com/pri/get/Public/ ... c2nOMS5ORA
Edit 4 April 2017 Revised link
Attachments
DEMO-MRI TreeControl.odb
May 2015 - Updated explanation in Demo file
April 2017 - Revised link
(45.1 KiB) Downloaded 490 times
When this issue has been resolved, it would help other users of the forum if you add the word - [Solved] - to the Subject line of your 1st post (edit button top right).
AOOo 4.1.5 & LO 6 on MS Windows 10 MySQL and HSQLDB
Post Reply