Dialog Modal with Basic IDE, Non-Modal with documents

I’ve noticed that if I start a dialog from a macro located in “My Macros & Dialogs”, running the macro from the Basic IDE (for example using ctrl-shift-F8), then the dialog started is modal with the basic IDE and not with the active document.

This can then be a problem trying to debug the macros called from events triggered by controls in the dialog.

I can work around this problem by first setting the document active, I’m using the following to set the current document active.

StarDesktop.loadComponentFromURL(ThisComponent.URL,"_default",0,array()) ' sets focus to the document'

Is there a better method than this to set the active focus to ThisComponent?

Edit. Slightly better method to change focus from the Basic IDE to the document when starting a modal dialog. Either the DoEvents or a Wait seems to be needed to avoid the dialog still being attached to the Basic IDE.

ThisComponent.CurrentController.Frame.ContainerWindow.setFocus
DoEvents

Also is there some similar method that could create a dialog that is non-modal with documents but without it being modal with the basic IDE?

I saw this prior question how-to-make-non-modal-dialog answered by @pierre-yves-samyn, but wondered if the above behaviour could lead to some other method.

Attached contains sample dialog and macro.
Untitled 29.ods

Note the macro module and dialog needs to be copied to “My Macros & Dialogs” to show the problem.

I’m using LibreOffice 5.2.1.2 x64 on Windows 8.1.

Edit to add code for fake non-modal dialog created using IDE and setting the dummy document invisible. Note the dialog is not shown in the windows task bar and can become hidden behind other windows. Also reference to ThisComponent will refer to the hidden dummy document.

Sub ShowHiddenDocDialog

    Dim oDummyDoc As Object
    Dim oController As Variant
    
    oDummyDoc = StarDesktop.loadComponentFromURL("private:factory/scalc", "_default", 0, array())
    oController = oDummyDoc.CurrentController
	
	DoEvents	'	Wait for the new document to be activated'
	
	DialogLibraries.LoadLibrary("Standard")
	MySampleDialog = CreateUnoDialog(DialogLibraries.Standard.DocIdentify)
	
	oController.Frame.ContainerWindow.Visible = False
	
	MySampleDialog.execute()
	
	oDummyDoc.close(true)
End Sub

Hello @mark_t

Hopefully I understand all your questions. First, access to controls. I do this by setting the dialog as a global object.

Global oHatchDialog As Object

Sub DisplayHatchDialog
Dim oUndoManager As Variant
Dim isLocked as Boolean
Dim oSheet As Object
oUndoManager = ThisComponent.getUndoManager()
oSheet = ThisComponent.CurrentController.ActiveSheet
Globalscope.BasicLibraries.LoadLibrary( "CalcHatchCellsLib" )
DialogLibraries.LoadLibrary("CalcHatchCellsLib")
oHatchDialog = CreateUnoDialog(DialogLibraries.CalcHatchCellsLib.getByName("HatchDialog"))
oHatchDialog.GetControl("HatchCountDisplay").Text = "Hatch Cells Applied = " & CountHatchCells
oHatchDialog.Execute()
oHatchDialog.dispose()
End Sub

The in other routines I then access the controls as such:

	oHatchDialog.GetControl("TextMessage").Text = "Ready for Processing"
oHatchDialog.GetControl("HatchCountDisplay").Text = "Hatch Cells Applied = " & CountHatchCells

Now for modal & non-modal. Typically a dialog is modal. Since you’re looking for a non-modal, I believe you are looking for something other than using the setVisible method - see my sample here. What sets this as non-modal (actually modal to desktop) is

	setProperties(oDlgModel, Array("PositionX", 50, "PositionY", 50,_
			"Width", iDlgWidth, "Height", iDlgHeight, "Title",_
			"Budget System - Average Expenses", "DesktopAsParent", True))

the desktopAsParent property. For properties see this link.

Hope this is what you are looking for.

Edit: Took a look at your sample. Made a couple of minor changes. Will display what is entered in Text line. Use Close button to end dialog.

Untitled30.ods

Thanks @Ratslinger, for the second part of my question I think the property “DesktopAsParent” is what I was looking for to create a non modal dialog without resorting to the setVisible method (which looks like it needs to keep the macro running while the dialog is open). I’ll test it out and post back later. I did find one other method, also quite messy, which was to create a new document, create the dialog and then set the new document invisible before executing the dialog.

In some cases I probably do want the dialog to be modal, in those cases the first part of my question can still be a problem during debug as the dialog becomes modal with the basic IDE. I think I found a slightly better workaround which I’ll edit in the question.

I had seen the global object method to access the controls, but I thought there was a possible problem if more than one dialog of the same type was open in different documents. It doesn’t seem difficult to use the oEvent object passed to the event handlers of controls to find oEvent.Source.Context to access other controls of the dialog.

Currently I have two modal dialogs opened and working on two different .ods files. No problem. Also opened the sample I sent you back (using global) from the IDE and read cell data. Also no problem.

I tried adding “MySampleDialog.Model.DesktopAsParent = True” using a dialog built by the IDE but this still opens the dialog as modal. Perhaps it only works when the dialog is built by the macro. I’ll try this sometime over the weekend.

The non-modal sample I pointed you to works as non-modal from the IDE. Also be aware in this case any code changes can be made but not saved or effective until the dialog closes. I do not know of any way around changing code and testing with it with a dialog open - either modal or non-modal. The dialogs’ code is executing while it is open preventing any code changes to be saved.

Building the Dialog from Basic macro and setting “.DesktopAsParent = True” during creation of the model is working to create the Dialog as Non-Modal.

If I create two separate dialogs they are non-modal with documents and the basic IDE, but seem to be modal with each other, in that only the last dialog created can be activated. I had similar issue with modal dialogs. I’ll try with Linux in case this is a windows issue and maybe post a new question when I can create a simple demo.

Code based on @Ratslinger answer, creates the dialog from basic macro setting DesktopAsParent.

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

Option Explicit	

Sub ID_CreateDialog

	Dim oDlgModel As Variant
	Dim sDialog As String
	
	sDialog = "DocIdentify"
	
	Dim oComponents As Variant
	Dim oDoc As Variant
	
	oDlgModel = CreateUnoService("com.sun.star.awt.UnoControlDialogModel")
	With oDlgModel
		.Name = sDialog
		.Title = "Doc Identify"
		.PositionX = 170
		.PositionY = 70
		.Width = 190
		.Height = 40
		.DesktopAsParent = True
	End With
	
	Dim oModel As Variant
	oModel = oDlgModel.createInstance("com.sun.star.awt.UnoControlEditModel")
	With oModel
		.TabIndex = 0
		.Name = "TextField1"
		.PositionX = 10
		.PositionY = 6
		.Width = 170
		.Height = 12
	End With
	oDlgModel.insertByName(oModel.Name, oModel)
	
	oModel = oDlgModel.createInstance("com.sun.star.awt.UnoControlButtonModel")
	With oModel
		.TabIndex = 1
		.Name = "CommandButton1"
		.Label = "Identify Active Document"
		.PositionX = 55
		.PositionY = 22
		.Width = 80
		.Height = 12
	End With
	oDlgModel.insertByName(oModel.Name, oModel)
	
	Dim oDlg As Variant
	oDlg = CreateUnoService("com.sun.star.awt.UnoControlDialog")
	oDlg.setModel(oDlgModel)
	
	Dim oListener As Variant
	Dim oControl As Variant
	oListener = CreateUnoListener("IDButton_", "com.sun.star.awt.XActionListener")
	oControl = oDlg.getControl("CommandButton1")
	ocontrol.addActionListener(oListener)
	
	Dim oWindow As Variant
	oWindow = CreateUnoService("com.sun.star.awt.Toolkit")
	
	oDlg.createPeer(oWindow, null)
	
	oDlg.execute()
End Sub

Sub IDButton_actionPerformed(oEvent As Variant)
'	Assigned to the button action event when dialog was created'

	Dim vTextfield As Variant
	
	vTextfield = oEvent.Source.Context.getControl("TextField1")
	
	vTextfield.Text = ThisComponent.URL
End Sub