How to save dynamically created subforms and controls in base

Hi community

I have developed a base application that programmatically:

  1. creates multiple Subform (linked to the parent) and add Textfield controls to the created Subform
  2. adds the new Subforms to the existing Form

Subforms and TextFields are created via Basic Macros. I now want to save the resulting Form and use it.

I have tried saving with the dispatcher (uno:Save, uno:SaveAll), after switching to design mode, without results.

The following manual process works:

  1. Edit the form
  2. Switch to Design mode so that macros are run
  3. Save

Here the navigator window showing the newly created subforms.

Any suggestions ?

Thanks

See the wonderful book “OpenOffice.org Base Macro Programming” by Andrew Pitonyak, section 2.3.2 (Create a Form) Using a macro.

Thank you sokol92

I extensively use this book already: my issue is not about creating forms, subforms controls etc from a macro. My topic is how to save the final result (what you see in my attached navigator picture).

Reading through the book’s lines it seems that the solution is not clear as I pointed out. Andrew states “…When I tested using AOO, the form was left in design mode, and you must exit design mode before you can test the control.”

In my case there are two scenarios:

  1. open the form via edit, running all the macros and saving the form preserves all the newly created fields
  2. opening the form by double click and runnning all the macros does not leave any side effect, evening by dispatching a save command

rgds

Andrew Pitonyak wrote his book in 2013 for OO. Since then there have been changes.
If you prepare an example (upload .odb file), then I think together we can figure it out.
Best wishes.

Found a similar topic. See my message there (#15).

1 Like

Hi Vladimir, I will study the topic you have mentioned as it provides clues into a potential solution. My intuitive approach was that, the form invoked, I was able to obtain its mode i.e. design or not and to a) force design prior adding subforms and controls, b) saving and finally switching out from Design mode. I crashed into a wall :slight_smile:

I have attached a shrink-wrapped version of the application.

If you launch the “Item Editor” form, you will see textfields popping up.

If you edit the “Item Editor” form and steps out from design, the textfields will pop up. You can the save the form and this will retain all the new elements.

My goal is to reproduce the latter use case from within the macro.

BTW: Ubuntu + LO 75.4.2
cti-extract.odb (45.1 KB)

In your example, the CacheInit macro is assigned to the form (Form) open event, which is hardly correct.
Look again at my example. In the example using a macro:

  1. Opens the form (text document) in Design mode (also hidden).
  2. Changes are made to this form - an event handler is added.
  3. The form is saved and closed without prompting the user.

You need to change part 2 to your own - subform generation.

See also XFormLayerAccess Interface. Example:

 ThisComponent.CurrentController.setFormDesignMode True  ' To design Mode

Ciao Vladimir, many thanks for your help. I guess you’re still referring to the post you’ve referred before yesterday. I will try the proposed approach and let you know. I still have a couple of questions:

  1. What is the issue with placing macros in the Form open event ? Is this something to avoid for specific reasons ?
  2. Is there an easy way to programmatically understand if the the context the macro is running is in design mode ? Looking at your code I could in theory go up to Document level for checking this …

Many thanks.

Hello Matteo!

  1. I meant that your goal is to change the form dynamically. Perhaps a more convenient place to do this is in the open event of the text document containing the form. Or the event of opening a database document.
  2. I think this is the right way - find (hierarchically) the parent text document and then communicate with its CurrentController.

Perhaps you are interested in this topic. In particular, @Villeroy 's examples show methods for finding the parent document.

Finding the embedded form document is not the problem. Like any other document, it has a store() method which raises some i/o error. There are more methods like storeSelf(args), storetostorage(args) but I’m not inclined to ivestigate on these.
All I can offer is a ready made macro to store the embedded forms as stand-alone Writer documents (which is the way to go IMHO): Apache OpenOffice Community Forum - FreeHSQLDB v.0.4 - (View topic) (module “FreeForms”)

Dear Andreas and Vladimir, many thanks for your help, really appreciated. I will mix both approaches and get to the desired result as I am now in a position to get the state (design or not) and save the result.

I have marked one reply as solution … as one can be selected at most

Ciao to both of you.

and what was the solution? How do you save the modified form design to its embedding database document? Or did you switch to stand-alone forms?

Workaround:

  1. Save the form (text document) to a file (.odt)
  2. Close the form
  3. Remove the form from the database document
  4. Add the saved file as a new form.

The following procedure is based on the AddBinForm macro from the book “OpenOffice.org Base Macro Programming” by Andrew Pitonyak.

' Add oDoc (opened text document) to oDBDoc (opened DatabaseDocument) Forms with name sFormName.
' Macro is based on the AddBinForm macro from the book "OpenOffice.org Base Macro Programming" by Andrew Pitonyak.
Sub AddFormToDbdoc(Byval oDoc As Object, Byval oDBDoc As Object, _
                   ByVal sFormName As String)
  Dim sDBName As String, s As String, sFormURL As String
  Dim oFormDocs As Object, oDocDef As Object
  Dim oProps(2) as new com.sun.star.beans.PropertyValue

  If NOT GlobalScope.BasicLibraries.isLibraryLoaded("Tools") Then
    GlobalScope.BasicLibraries.LoadLibrary("Tools")
  End If

  sDBName = GetFileNameWithoutExtension(oDBDoc.Url, "/")
  s$ = DirectoryNameoutofPath(oDBDoc.Url, "/") & "/"
  sFormURL = s$ & "Form_" & sDBName & "_Temp.odt"

  ' Store the form to disk and then close the document.
  oDoc.StoreToUrl(sFormUrl, Array())
  oDBDoc.CurrentController.CloseSubComponents

  ' Now, convert the form on disk to a document defition and
  ' store it in a Base document.
  oFormDocs = oDBDoc.getFormDocuments()
  If oFormDocs.hasByName(sFormName) Then
    ' Print "Removing " & sFormName & " from the database"
    oFormDocs.removeByName(sFormName)
  End If

  oProps(0).Name = "Name"
  oProps(0).Value = sFormName
  oProps(1).Name = "Parent"
  oProps(1).Value = oFormDocs()
  oProps(2).Name = "URL"
  oProps(2).Value = sFormUrl
  s$ = "com.sun.star.sdb.DocumentDefinition"
  oDocDef = oFormDocs.createInstanceWithArguments(s$, oProps())
  oFormDocs.insertbyName(sFormName, oDocDef)
  ' Print "Added " & sFormName & " to the database"

End Sub

My attempt to save the mods to the embedded form miserably failed : exceptions are raised as soon as you try to store things. I tried to hike and study the component hierarchy (form, form document, forms …) without any tangible result. Very frustrating experience.

I will fall-back to your proposed solutions of working and playing around with an external form :will however not surrender and search for a solution to save an embedded form.

Villeroy extensive experience with external forms is more than convincing. This will also allow me to improve change management e.g. distributing forms only vs. The entire db.

Many thanks.