LibreOffice Developer's Guide: Chapter 11 - LibreOffice Basic

    From The Document Foundation Wiki
    • First Steps with LibreOffice Basic guides you through the necessary steps to write LibreOffice Basic UNO Programs.
    • LibreOffice Basic IDE provides a reference to the functionality of the LibreOffice Integrated Development Environment (IDE). It describes:
      • The dialogs to manage Basic and dialog libraries.
      • The functionality of the Basic IDE window: the Basic macro editor and debugger, and the Dialog editor.
      • The assignment of macros to events
    • Features of LibreOffice Basic describes the Basic programming language integrated in LibreOffice, including
      • Provides an overview about the general language features built into LibreOffice Basic.
      • Extends the UNO language binding chapter LibreOffice Basic by information on how to access the application specific UNO API.
      • Points out threading and rescheduling characteristics of LibreOffice Basic that differ from other languages, such as, from Java, which can be important under certain circumstances.
    • Advanced Library Organization describes how the Basic library system stores and manages Basic macros and dialogs in LibreOffice, and how the user can access libraries and library elements using the appropriate interfaces.
    • Programming Dialogs and Dialog Controls describes the toolkit controls used to create dialogs in the dialog editor. In this section the different types of controls and their specific properties are explained in detail.
    • Creating Dialogs at Runtime describes how UNO dialogs can be created at runtime without using the dialog editor. This is useful to show dialogs from UNO components. As this is an advanced way to create dialogs, this section goes deeply into the Toolkit interfaces and extends the section Programming Dialogs and Dialog Controls.
    • Library File Structure discusses the various files used by the Basic IDE.
    • Library Deployment discusses the automatic deployment of Basic libraries into a local or a shared LibreOffice installation.

    First Steps with LibreOffice Basic

    Step By Step Tutorial

    This section provides a tutorial to enable developers to use the Basic IDE. It describes the necessary steps to write and debug a program in the Basic IDE, and to design a Basic dialog. A comprehensive reference of all tools and options can be found at LibreOffice Basic IDE.

    Creating a Module in a Standard Library

    1. Create a new Writer document and save the document, for example, FirstStepsBasic.odt.
    2. Click Tools ▸ Macros ▸ Organize Macros ▸ LibreOffice Basic.

    The LibreOffice Basic Macros dialog appears. The Macro from list shows macro containers where Basic source code (macros) can come from. There is always a My Macros and a OpenOffice Macros container for Basic libraries. Additionally, each loaded document can contain Basic libraries.

    Macro dialog

    The illustration above shows that the document FirstStepsBasic.odt is the only document loaded. Therefore, the My Macros, OpenOffice Macros and FirstStepsBasic.odt containers are displayed in the illustration above. Both containers, My Macros and FirstStepsBasic.odt, contain a library named Standard. The OpenOffice Macros container contains the libraries that come with a default LibreOffice installation – most of them are AutoPilots. The Standard libraries of the application and for all open documents are always loaded. They appear enabled in the dialog. Other libraries have to be loaded before they can be used.

    The libraries contain modules with the actual Basic source code. Our next step will create a new module for source code in the Standard library of our FirstStepsBasic.odt document.

    1. Scroll to the document node FirstStepsBasic.odt in the Macro from list.
    2. Select the Standard entry below the document node and click New.

    LibreOffice shows a small dialog that suggests to create a new module named Module1.

    1. Click OK to confirm.

    The Basic source editor window appears containing a Sub (subroutine) Main.

    Basic source editor window

    The status bar of the Basic editor window shows that the Sub Main is part of FirstStepsBasic.Standard.Module1. If you click Tools ▸ Macros ▸ Organize Macros ▸ LibreOffice Basic in the Basic editor, you will see that LibreOffice created a module Module1 below the Standard library in FirstStepsBasic.odt.

    The New Module window

    When a module is selected, the Macro name list box on the left shows the Subs and Functions in that module. In this case, Sub Main. If you click Edit while a Sub or Function is selected, the Basic editor opens and scrolls to the selected Sub or Function.

    Writing and Debugging a Basic UNO program

    Enter the following source code in the Basic editor window. The example asks the user for the location of a graphics file and inserts it at the current cursor position of our document. Later, the example will be extended by a small insert graphics autopilot.

    Sub Main
        ' ask the user for a graphics file
        sGraphicUrl = InputBox("Please enter the URL of a graphic file", _
            "Import Graphics", _
            "file:///")
        if sGraphicURL = "" then ' User clicked Cancel
            exit sub
        endif
    
        ' access the document model
        oDoc = ThisComponent
    
        ' get the Text service of the document
        oText = oDoc.getText()
    
        ' create an instance of a graphic object using the document service factory
        oGraphicObject = oDoc.createInstance("com.sun.star.text.GraphicObject")
    
        ' set the URL of the graphic
        oGraphicObject.GraphicURL = sGraphicURL
    
        ' get the current cursor position in the GUI and create a text cursor from it
        oViewCursor = oDoc.getCurrentController().getViewCursor()
        oCursor = oText.createTextCursorByRange(oViewCursor.getStart())
    
        ' insert the graphical object at the cursor position
        oText.insertTextContent(oCursor.getStart(), oGraphicObject, false)
    End Sub

    If help is required on Basic keywords, press F1 while the text cursor is on a keyword. The LibreOffice online help contains descriptions of the Basic language as supported by LibreOffice.

    Starting with the line oDoc = ThisComponent, where the document model is accessed, we use the UNO integration of LibreOffice Basic. ThisComponent is a shortcut to access a document model from the Basic code contained in it. Earlier, you created Module1 in FirstStepsBasic.odt, that is, your Basic code is embedded in the document FirstStepsBasic.odt, not in a global library below the My Macros container. The property ThisComponent therefore contains the document model of FirstStepsBasic.odt.

    Tip.svg

    Tip:
    Outside document libraries use ThisComponent or StarDesktop.CurrentComponent to retrieve the current document. If access to an open document is required, even if it is not the current document, you have to iterate over the components in StarDesktop.Components, checking their URL property with code similar to the following:

    oComps = StarDesktop.Components
    oCompsEnum = oComps.createEnumeration()
    
    while oCompsEnum.hasMoreElements()
        oComp = oCompsEnum.nextElement()
        ' not all desktop components are necessarily models with a URL
        if HasUnoInterfaces(oComp, "com.sun.star.frame.XModel") then
        print oComp.getURL()
        endif
    wend


    Breakpoint.png To debug the program, put the cursor into the line oDoc = ThisComponent and click the Breakpoint icon in the macro bar.
    MacroRun.png The Run icon launches the first Sub in the current module. Execution stops with the first breakpoint.
    SingleStep.png Now step through the program by clicking the Single Step icon.
    Macros.png Click the Macros icon if you need to run a Sub other than the first Sub in the module.. In the LibreOffice Basic Macros dialog, navigate to the appropriate module, select the Sub to run and press the Run button.

    To observe the values of Basic variables during debugging, enter a variable name in the Watch field of the Basic editor and press the ↵ Enter key to add the watch, or point at a variable name with the mouse cursor without clicking it. In the example below, we can observe the variables sGraphicUrl and oGraphicObject:

    A macro in the source editor window

    Since OpenOffice.org 2.0.0 it is also possible to inspect the values of UNO objects in the Basic debugger during runtime.

    Calling a Sub from the User Interface

    A Sub can be called from customized icons, menu entries, upon keyboard shortcuts and on certain application or document events. The entry point for all these settings is the Customize dialog accessible through the Assign button in the Macro dialog or the Tools ▸ Customize command.

    To assign the Sub Main to a toolbar icon, select Tools ▸ Customize and click the Toolbars tab. The Toolbars tab looks like this:

    Customize Toolbars

    Click the Add button in the Toolbars tab. In the Add Commands dialog that pops up, scroll down the Category list until you see the Application Macros node. Expand it and the FirstStepsBasic.odt node. Navigate to the Module FirstStepsBasic.Standard.Module1 and select it. When Module1 is selected, the Commands list shows an entry "Main" for the Sub Main in Module1. Clicking Add will add it to a toolbar.

    You can now click the new toolbar item to launch the example macros.

    The section Assigning Macros to GUI Events describes other options to make your Sub accessible from the user interface.

    Creating Dialogs

    To create a dialog in the Basic IDE, right-click the Module1 tab at the bottom of the Basic source editor and select Insert ▸ Basic Dialog. The IDE creates a new page named Dialog1:

    The Basic GUI Editor
    Controls.png To add controls to the dialog, we require the dialog design tools. Click the Controls icon to pop up the design tools window. The title bar of the tools window can be used to drag the window away from the toolbar to keep it open permanently.

    Our dialog shall offer a more convenient way to select a file than the simple input box of our first example. Furthermore, the user shall be able to control how the picture is anchored in the text after inserting it. For this, we will create a wizard dialog with two steps.

    FileSelection.png In the design tools window, select File Selection and define the size of the Browse control by dragging a rectangle in the dialog using the left-mouse button.
    ControlProperties.png The Properties icon displays the Properties Dialog that is used to edit controls and hook up event handling code to events occurring at dialog controls.
    ButtonControl.png Next, add << Back and Next >> buttons to move between the dialog steps, and a Finish and Cancel button. Select the Button icon and define the button size using the left-mouse button. Buttons are labeled with a default text, such as CommandButton1. If the Properties Dialog is not open, double-click the newly inserted button controls to display it. Enter new labels in the Label field as suggested, and name the dialog step buttons Back and Next. Set the property Enabled for the << Back button to false.
    LabelControl.png Use the Label tool to create a label "Select Graphics File:" in the same manner.

    Now the dialog looks similar to the illustration below:

    The custom dialog
    ActivateTestMode.png Test the dialog using the Activate Test Mode icon from the design tool window. After you have finished the test, click the Close button of the test dialog window.

    To edit the dialog, such as setting the title and changing the size, select it by clicking the outer border of the dialog. Green handles appear around the dialog. The green handles can be used to alter the dialog size. The Properties Dialog is used to define a dialog title and other dialog properties.

    Adding Event Handlers

    Now we will write code to open the dialog and add functionality to the buttons. To show a dialog, create a dialog object using createUnoDialog() and call its execute() method. A dialog can be closed while it is shown by calling endExecute().

    Tip.svg

    Tip:
    It is possible to configure the Finish button and the Cancel button to close the dialog by setting the button property PushButtonType to OK and Cancel respectively. The method execute() returns 0 for Cancel and 1 for OK.


    To add functionality to GUI elements, develop Subs to handle GUI events, then hook them to the GUI elements. To add functionality to the buttons of our dialog, click the Module1 tab in the lower part of the Basic IDE and enter the following Subs above the previous Sub Main to open, close and process the dialog. Note that a Private variable oDialog is defined outside the Subs. After loading the dialog, this variable is visible from all Subs and Functions of Module1.

    Private oDialog as Variant ' private, module-wide variable
    
    Sub RunGraphicsWizard
        oDialog = createUnoDialog(DialogLibraries.Standard.Dialog1)
        oDialog.execute
    End Sub
    
    Sub CancelGraphicsDialog
        oDialog.endExecute()
    End Sub
    
    Sub FinishGraphicsDialog
        Dim sFile as String, sGraphicURL as String
    
        oDialog.endExecute()
    
        sFile = oDialog.Model.FileControl1.Text
    
        ' the FileControl contains a system path, we have to transform it to a file URL
        ' We use the built-in Basic runtime function ConvertToURL for this purpose
        sGraphicURL = ConvertToURL(sFile)
    
        ' insert the graphics
        ' access the document model
        oDoc = ThisComponent
        ' get the Text service of the document
        oText = oDoc.getText()
        ' create an instance of a graphic object using the document service factory
        oGraphicObject = oDoc.createInstance("com.sun.star.text.GraphicObject")
        ' set the URL of the graphic
        oGraphicObject.GraphicURL = sGraphicURL
        ' get the current cursor position in the GUI and create a text cursor from it
        oViewCursor = oDoc.getCurrentController().getViewCursor()
        oCursor = oText.createTextCursorByRange(oViewCursor.getStart())
        ' insert the graphical object at the cursor position
        oText.insertTextContent(oCursor.getStart(), oGraphicObject, false)
    End Sub
    
    Sub Main
        ...
    End Sub

    Select the Cancel button in our dialog in the dialog editor, and click the Events tab of the Properties Dialog, then click the ellipsis button on the right-hand side of the Event Execute action. As shown in the next illustration the Assign Action dialog appears.

    Assign Action dialog

    In the Assign Action dialog press the Macro… button to open the Macro Selector dialog shown in the illustration below. Navigate to FirstStepsBasic.Standard.Module1, select the Sub CancelGraphicsDialog and press the OK button to link this sub to the wizard dialog's Cancel button.

    The Macro Selector dialog

    The next illustration shows how the new assignment is shown in the Assign Action dialog.

    The Assign Action dialog

    Pressing the OK button in the Assign Action dialog finishes the assignment process.

    Note pin.svg

    Note:
    In the Assign Action dialog there's also a Component… button. This button is only needed in the context of dialogs used by UNO components, see Accessing Dialogs. In the Basic context this button is not relevant.

    Using the same method, hook the Finish button to FinishGraphicsDialog.

    MacroRun.png If the Run icon is selected now, the dialog is displayed, and the Finish and Cancel buttons are functional.

    AutoPilot Dialogs

    The final step is to create a small AutoPilot with two pages. The LibreOffice Dialogs have a simple concept for AutoPilot pages. Each dialog and each control in a dialog has a property Page (Step) to control the pages of a dialog. Normally, dialogs are on page 0, but they can be set to a different page, for example, to page 1. All controls having 1 in their Page property are visible as long as the dialog is on page 1. All controls having 2 in their page property are only displayed on page 2 and so forth. If the dialog is on Page 0, all controls are visible at once. If a control has its Page property set to 0, it is visible on all dialog pages.

    This feature is used to create a second page in our dialog. Hold down the Ctrl key, and click the label and file control in the dialog to select them. In the Properties Dialog, fill in 1 for the Page property and press Enter to apply the change. Next, select the dialog by clicking the outer rim of the dialog in the dialog editor, enter 2 for the Page property and press the ↵ Enter key. The label and file control disappear, because we are on page 2 now. Only the buttons are visible since they are on page 0.

    On page 2, add a label "Anchor" and two option buttons "at Paragraph" and "as Character". Name the option buttons AtParagraph and AsCharacter, and toggle the State property of the AtParagraph button, so that it is selected by default. The new controls automatically receive 2 in their Page property. When page 2 is finished, set the dialog to page 1 again, because we want it to be on page 1 on startup.

    The Insert Graphics Wizard

    The Subs below handle the << Back and Next >> buttons, and the Sub FinishGraphicsDialog has been extended to anchor the new graphics selected by the user. Note that the property that is called Page (Step) in the GUI, is called Step in the API.

    Sub BackGraphicsDialog
        oDialog.Model.Step = 1
        oDialog.Model.Back.Enabled = false
        oDialog.Model.Next.Enabled = true
    End Sub
    
    Sub NextGraphicsDialog
        oDialog.Model.Step = 2
        oDialog.Model.Back.Enabled = true
        oDialog.Model.Next.Enabled = false
    End Sub
    
    Sub FinishGraphicsDialog
        Dim sGraphicURL as String, iAnchor as Long
        oDialog.endExecute()
        sFile = oDialog.Model.FileControl1.Text
        ' State = Selected corresponds to 1 in the API
        if oDialog.Model.AsCharacter.State = 1 then
            iAnchor = com.sun.star.text.TextContentAnchorType.AS_CHARACTER
        elseif oDialog.Model.AtParagraph.State = 1 then
            iAnchor = com.sun.star.text.TextContentAnchorType.AT_PARAGRAPH
        endif
        ' the File Selection control returns a system path, we have to transform it to a File URL
        ' We use the built-in Basic runtime function ConvertToURL for this purpose
        sGraphicURL = ConvertToURL(sFile)
        ' access the document model
        oDoc = ThisComponent
        ' get the Text service of the document
        oText = oDoc.getText()
        ' create an instance of a graphic object using the document service factory
        oGraphicObject = oDoc.createInstance("com.sun.star.text.GraphicObject")
        ' set the URL of the graphic
        oGraphicObject.GraphicURL = sGraphicURL
        oGraphicObject.AnchorType = iAnchor
        ' get the current cursor position in the GUI and create a text cursor from it
        oViewCursor = oDoc.getCurrentController().getViewCursor()
        oCursor = oText.createTextCursorByRange(oViewCursor.getStart())
        ' insert the graphical object at the beginning of the text
        oText.insertTextContent(oCursor.getStart(), oGraphicObject, false)
    End Sub

    LibreOffice Basic IDE

    This section discusses all features of the Integrated Development Environment (IDE) for LibreOffice Basic. It shows how to manage Basic and dialog libraries, discusses the tools of the Basic IDE used to create Basic macros and dialogs, and it treats the various possibilities to assign Basic macros to events.

    Managing Basic and Dialog Libraries

    The main entry point to the library management UI is the Tools ▸ Macros ▸ Organize Macros ▸ LibreOffice Basic menu item. This item activates the LibreOffice Basic Macros dialog where the user can manage all operations related to Basic and dialog libraries.

    LibreOffice Basic Macros Dialog

    The following picture shows an example macro dialog. From here you can run, create, edit and delete macros, assign macros to UI events, and administer Basic libraries and modules.

    The macro dialog
    Displayed Information

    The tree titled with Macro from shows the complete library hierarchy that is available the moment the dialog is opened. See Advanced Library Organization for details about the library organization in LibreOffice.

    Unlike the library organization API, this dialog does not distinguish between Basic and dialog libraries. Usually the libraries displayed in the tree are both Basic and dialog libraries.

    Note pin.svg

    Note:
    Although it is possible to create Basic-only or dialog-only libraries using the API this is not the normal case, because the graphical user interface (see LibreOffice Basic Macro Organizer Dialog below) only allows the creation of Basic and dialog libraries simultaneously. Nevertheless, the dialog can also deal with Basic-only or dialog-only libraries, but they are not marked in any way.

    The tree titled Macro from represents a structure consisting of three levels:

    Library container -> library -> library element

    • The top-level nodes represent the application Basic and dialog library container (nodes My Macros and OpenOffice Macros). For each opened document, the document's Basic and dialog library container (see Advanced Library Organization). In the example two documents are open, a text document called Description.odt and a spreadsheet document named Calculation.ods.
    • In the second level, each node represents a library. Initially all libraries, except the default libraries named Standard, are not loaded and grayed out. To load a library, the user double-clicks the library. In the example above, the My Macros root element contains the Standard library, already loaded by default.
    • The third level in the tree is visible in loaded libraries. Each node represents a library element that can be modules or dialogs. In the LibreOffice Basic Macros dialog, only Basic modules are displayed as library elements, whereas dialogs are not shown. By double-clicking a library the user can expand and condense a library to show or hide its modules. In the example, the My Macros/Standard library is displayed expanded. It contains two modules, Module1 and Module2. The document Description.odt contains a Standard library with one Basic module Module1. Calculation.ods contains a Standard library without Basic modules. All libraries, respectively their dialog library part, may also contain dialogs that cannot be seen in this view.

    If a library is password-protected and a user double-clicks it to load it, a dialog is displayed requesting a password. The library is only loaded and expanded if the user enters the correct password. If a password-protected library is loaded using the API, for example, through a call to BasicLibraries.loadLibrary("Library1"), it is displayed as loaded, not grayed out, but it remains condensed until the correct password is entered (see Advanced Library Organization).

    The middle column contains information about the macros, that is, the Subs and Functions, in the libraries. In the list box at the bottom, all Subs and Functions belonging to the module selected in the tree are listed. In the edit field titled Macro name, the Sub or Function currently selected in the list box is displayed. If there is no module selected in the tree, the edit field and list are empty. You can type in a desired name in the edit field.

    Buttons

    On the right-hand side of the LibreOffice Basic Macros dialog, there are several buttons. The following list describes the buttons:

    • Run
    Executes the Sub or Function currently displayed in the Macro name edit field. The LibreOffice Basic Macros dialog is closed, before the macro is executed.
    • Close
    Closes the LibreOffice Basic Macros dialog without any further action.
    • Assign
    Opens the Customize dialog that can also be opened using Tools - Customize. This dialog can be used to assign Basic macros to events. For details see Assigning Macros to GUI Events below.
    • Edit
    Loads the module selected in the tree into the Basic macro editor. The cursor is placed on the first line of the Sub or Function displayed in the Macro name edit field. See chapter Basic IDE Window below for details about the Basic macro editor. This button is disabled if there is no module selected in the tree or no existing Sub or Function displayed in the Macro name edit field.
    • Delete
    This button is only available if an existing Sub or Function is displayed in the Macro name edit field. The Delete button removes the Sub or Function displayed in the Macro name edit field from the module selected in the module selected in the tree.
    • New
    This button is only available if no existing Sub or Function is displayed in the Macro name edit field. The New button inserts a new Sub into the module selected in the tree. The new Sub is named according to the text in the Macro name edit field. If Macro name is empty, the Sub is automatically named Macro1, Macro2, and so forth.
    • Organizer
    This button opens the LibreOffice Basic Macro Organizer dialog box that is explained in the next section.
    • Help
    Starts the LibreOffice help system with the Macros topic.

    LibreOffice Basic Macro Organizer Dialog

    This dialog is opened by clicking the Button Organizer in the LibreOffice Basic Macros dialog. The dialog contains the tab pages Modules, Dialogs and Libraries. While the LibreOffice Basic Macros dialog refers to Subs and Functions inside Basic modules, such as run Subs, delete Subs, and insert new Subs, this dialog accesses the library system on module (tab page Modules) , dialog (tab page Dialogs) and library (tab page Libraries) level.

    Modules

    Illustration 12.13 shows the LibreOffice Basic Macro Organizer dialog with the Modules tab page activated. The list titled Module is similar to the Macro from list in the Macro dialog, but it contains the complete library hierarchy for the LibreOffice application libraries and the document libraries. The libraries are loaded, and condensed or expanded by double-clicking the library. The illustration shows the application library Standard containing two modules, Module1 and Module2.

    The Macro Organizer

    The illustration above shows that two documents are loaded. The illustration shows a library Standard in document Description.odt containing a module named Module1, and another library Standard in document Calculation.ods containing no Basic module.

    The following list describes the buttons on the right side of the dialog:

    • Edit
    Loads the module selected in the tree into the Basic macro editor. If a module is not selected, this button is disabled.
    • Close
    Closes the LibreOffice Basic Macro organizer dialog without any further action.
    • New Module
    Opens a dialog that allows the user to type in the desired name for a new module. The name edit field initially contains a name like Module<Number>, such as Module1 and Module2, depending on the modules already existing. Clicking the OK button adds the new module as a new item in the Module list. The New Module button is disabled if the selected library has read-only status.
    • Delete
    Deletes the selected module. This button is disabled if no module is selected, or if the selected module belongs to a library with read-only status.
    Dialogs

    The illustration below shows the LibreOffice Basic Macro Organizer dialog with the Dialogs tab page activated. The illustration shows the application library Standard containing two dialogs, Dialog1 and Dialog2.

    The macro Organizer dialog

    The illustration shows a library Standard in document Calculation.ods containing a dialog named Dialog1, and another library Standard in document Description.odt containing no dialog.

    The following list describes the buttons on the right side of the dialog:

    • Edit
    Loads the dialog selected in the tree into the Dialog editor. The section Dialog Editor below describes the Dialog Editor in more detail. If a dialog is not selected, this button is disabled.
    • Close
    Closes the LibreOffice Basic Macro organizer dialog without any further action.
    • New Dialog
    Opens a dialog that allows the user to enter the desired name for a new dialog. The name edit field initially contains the name Dialog<Number>, such as Dialog1 and Dialog2, depending on the dialogs already existing. Clicking the OK button creates the dialog in the Dialog list. This button is disabled if the selection contains a library with read-only status.
    • Delete
    Deletes the selected dialog. This button is disabled if no dialog is selected, or if the selected dialog belongs to a library with read-only status.
    Libraries

    The following illustrations show the LibreOffice Basic Macro Organizer dialog with the Libraries tab page activated. In this dialog, the application and document libraries are listed separately. The Library list only contains the libraries of the library container currently selected in the Location list box. The second illustration is dropped down showing the My Macros & Dialogs and OpenOffice Macros & Dialogs entries and the two open documents.

    The Libraries tab page in the Macro Organizer dialog
    The Libraries tab page showing the Application/Document selection

    The libraries are displayed in the following manner:

    • Regular libraries are displayed in black.
    • Libraries with read-only status are grayed out.
    • Library links are followed by an URL indicating the location where the library is stored. In the example above, all libraries except for Standard and Library1 are library links and all library links have read-only status.
    • Password protected libraries are indicated with a key symbol before the name. In the example, only Library1 is password protected.

    Clicking a library twice (not double-click) allows the user to rename it.

    The following list describes the buttons on the right side of the dialog:

    • Edit
    Loads the first module of the library selected in the Library list box into the Basic macro editor (see Basic Source Editor and Debugger below). If the library only contains dialogs, the first dialog of the corresponding dialog library is displayed in the Dialog editor (see Dialog Editor below). If the Basic/Dialog editor window does not exist, it is opened.
    • Close
    Closes the LibreOffice Basic Macro Organizer dialog without any further action.
    • Password
    Opens the Change Password dialog displayed in the next illustration for the library currently selected in the Library list box.
    This dialog is used to change the password if the library is already password protected. Enter the old password first, then the new password twice.
    If the library is not password protected, the Old password edit field is disabled. The new password is entered twice in the New password section. Clicking OK activates the password protection if both passwords match.
    The Change Password dialog
    • New
    Opens a dialog allowing the user to enter the name for a new library. The name edit field initially contains the name Library<Number>, such as Library1 and Library2, depending on the libraries already existing. Clicking the OK button creates the library and adds it to the Library list. A new library is always created as a Basic and dialog library.
    • Import
    This button is used to import additional libraries into the library container that is selected in the Location list box. The button opens a file dialog where the user selects the location where the library is imported from. The following types of files can be selected:
    • Library container index files (script.xlc or dialog.xlc)
    • Library index files (script.xlb or dialog.xlb)
    • LibreOffice documents (e.g. *.odt, *.ods, *.sxw, *.sxc, *.sdw, *.sdc)
    • Star Office 5.x and previous Basic library files (*.sbl)
    After selecting a file, an Import library dialog is displayed. The next illustration shows the dialog after selecting a library index file script.xlb. The dialog displays all libraries that are found in the chosen file. In this example, only the library Euro appears, because the file script.xlb only represented this library.
    The Import Libraries dialog
    The checkboxes in the Options section, when selected, indicates if a library is inserted as a read-only link and if existing libraries with the same name are replaced by the new library.
    The next illustration shows the dialog after selecting the writer document LibraryImportExample. This document contains the four libraries Standard, Library1, Library2 and Library3. The illustration shows that the libraries Library1 and Library2 are selected for import. The Insert as reference (read-only) option is disabled, because the libraries inside documents cannot be referenced as a link. As well, StarOffice 5.x Basic library files can not be linked.
    The Import Libraries dialog with selected libraries
    Clicking the OK button imports the selected libraries into the library container that was previously selected in the Location list box, including the Basic and dialog libraries.
    • Export
    This button is used to export a library. The Standard library cannot be exported. Clicking the button displays the Export Basic library dialog.
    The Export Basic Library dialog
    This dialog allows to chose between two export formats. Choosing Export as package and clicking OK opens the Export library as package file dialog allowing to save the library in the UNO package bundle format that can be easily imported from other LibreOffice installations using the Package Manager available in the Tools menu. So this format should be used for deploying Basic libraries.
    The Export library as package dialog
    Choosing Export as BASIC library in the Export Basic library dialog opens the Export as BASIC library dialog allowing to choose a location where the library will be stored as folder named like the library. This format can be accessed with the Import functionality described above.
    The Export as BASIC library dialog
    The exported libraries always contain both Basic Modules and Dialogs.
    • Delete
    Deletes the item selected in the Library list box. If the item represents a library link, only the link is removed, not the library itself. The Delete button appears disabled whenever a Standard library is selected, because Standard libraries cannot be deleted.

    Basic IDE Window

    The LibreOffice IDE is mainly represented by the Basic IDE window. The IDE window has two different modes:

    • The Basic editor mode displays and modifies Basic source code modules to control the debugging process and display the debugger output
    • The dialog editor mode displays and modifies dialogs.

    Basic source code and dialogs are never displayed at the same time. The IDE window is in Basic editor or debugger, or in dialog editor mode. The following illustration shows the Basic IDE window in the Basic editor mode displaying Module2 of the application Standard library.

    The Basic IDE window

    The IDE window control elements common to the Basic editor and dialog editor mode are described below. The mode specific control elements are described in the corresponding subchapters Basic Source Editor and Debugger and Dialog Editor:

    • Clicking the Printer button in the main toolbar prints the displayed Basic module or dialog directly without displaying a printer dialog.
    • The Save button in the main toolbar behaves in two different ways depending on the library currently displayed in the IDE window.
      • If the library belongs to the application library container, the Save button saves all modified application libraries.
      • If the library belongs to a document, the Save button saves the document.
    • On the left-hand side of the toolbar, a Library list box shows the currently displayed library. The user can also modify the displayed library. In the example above, the Standard library of the application Basic ([My Macros & Dialogs].Standard) is displayed. The list box contains all the application and document libraries that are currently accessible. The user can select one to display it in the IDE window.
    • The tabs at the bottom of the IDE window indicate all the modules and dialogs of the active library. Clicking one of these tabs activates the corresponding module or dialog. If necessary, the IDE window switches from Basic editor to dialog editor mode or conversely. Right-clicking a tab opens a context menu:
      • Insert opens a sub menu to insert a new module or dialog.
      • Delete deletes the active module or dialog after confirmation by the user.
      • Rename changes the name of the active module or dialog.
      • Hide makes the active module or dialog invisible. It no longer appears as a tab flag, thus it cannot be activated. To activate, access it directly using the LibreOffice Basic Macros or LibreOffice Basic Macro Organizer dialog and clicking the Edit button.
      • Modules opens the LibreOffice Basic Macro Organizer dialog.
    • The status bar displays the following information:
      • The first cell on the left displays the fully qualified name of the active module or dialog in the notation LibraryContainer.LibraryName.<ModuleName | DialogName>.
      • The second cell displays an asterisk "*" indicating that at least one of the libraries of the active library container has been modified and requires saving.
      • The third cell displays the current position of the cursor in the Basic editor window.
      • The fourth cell displays "INSRT" if the Basic editor is in insertion mode and "OVER" if the Basic editor is in overwrite mode. The modes are toggled with the Insert key.

    Basic Source Editor and Debugger

    The Basic editor and debugger of the IDE window is shown when the user edits a Sub or Function from the Tools - Macros - Organize Macros - LibreOffice Basic dialog. In this mode, the window contains the actual editor main window, debugger Watch window to display variable values and the debugger Calls window to display the Basic call stack. The Watch and Calls windows are only used when a Basic program is running and halted by the debugger.

    The editor supports common editor features. Since the editor is only used for the LibreOffice Basic programming language, it supports a Basic syntax specific highlighting and F1 help for Basic keywords.

    Basic Editor and Debugger

    The following list explains the functionality of the macro toolbar buttons.

    Compile.png Compile: Compiles the active module and displays an error message, if necessary. This button is disabled if a Basic program is running. Always compile libraries before distributing them.
    MacroRun.png Run: Executes the active module, starting with the first Sub in the module, before all modified modules of the active library are compiled. Clicking this button can also result in compiler errors before the program is started. This button resumes the execution if the program is halted by the debugger.
    Stop.png Stop: Stops the Basic program execution. This button is disabled if a program is not running.
    StepOver.png Procedure Step: Executes one Basic statement without stepping into Subs or Functions called in the statement. The execution is halted after the statement has been executed. If the Basic program not is running the execution is started and halted at the first statement of the first Sub in the current module.
    SingleStep.png Single Step: Executes one Basic statement. If the statement contains another Sub, execution is halted at the first statement of the called Sub. If no Subs or Functions are called in the statement, this button has the same functionality as the Step over button (key command F8).
    StepOut.png Step back: Steps out of the current executed Sub or Function and halts at the next statement of the caller Sub or Function. If the currently executed Sub or Function was not called by another Sub or Function or if the Basic program is not running, this button has the same effect as the Run button.
    Breakpoint.png Breakpoint: Toggles a breakpoint at the current cursor line in the Basic editor. If a breakpoint can not be set at this line a beep warns the user and the action is ignored (key command F9). A breakpoint is displayed as a red dot in the left column of the editor window.
    AddWatch.png Add watch: Adds the identifier currently touched by the cursor in the Basic editor to the watch window (key command F7).
    ObjectCatalog.png Object Catalog: Opens the Objects dialog. This dialog displays the complete library hierarchy including dialogs, modules and the Subs inside the modules.
    Macros.png Macros: Opens the LibreOffice Basic Macros dialog.
    Modules.png Modules: Opens the LibreOffice Basic Macro Organizer dialog
    FindParentheses.png Find Parentheses: If the cursor in the Basic editor is placed before a parenthesis, the matching parenthesis is searched. If a matching parenthesis is found, the code between the two parentheses is selected, otherwise the user is warned by a beep.
    Controls.png Controls: Opens the dialog editing tools in the dialog editor. In Basic editor mode this button is disabled.
    OpenBasicSource.png Insert Source File: Displays a file open dialog and inserts the selected text file (*.bas is the standard extension) at the current cursor position into the active module.
    StoreBasicSource.png Save Source As: Displays a file Save As dialog to save the active module as a text file (*.bas is the standard extension).

    Illustration 12.24: Basic Editor and Debugger shows how the IDE window looks while a Basic program is executed in debugging mode.

    • The Stop button is enabled.
    • A breakpoint is set in line 11.
    • The execution is halted in line 12. The current position is marked by a yellow arrow.
    • The Watch window contains the entries Value and Hello, and displays the current values of these variables. Values of variables can also be evaluated by touching a corresponding identifier in the source code with the cursor.
    • The Calls window shows the stack. The currently executed Sub doIt is displayed at the top and the Sub Main at the second position.

    Dialog Editor

    This section provides an overview of the Dialog editor functionality. The controls that are used to design a dialog are not explained. See Programming Dialogs and Dialog Controls for details on programming these controls. The dialog editor is activated by creating a new dialog, clicking a dialog tab at the bottom of the IDE window, or selecting a dialog in the LibreOffice Basic Macro Organizer dialog and clicking the Edit button.

    Initially, a new dialog consists of an empty dialog frame. The next illustration shows Dialog2 of the application Standard library in this state.

    The dialog editor

    In the dialog editor mode, the Controls button is enabled and the illustration shows the result by clicking this button. A small toolbar with dialog specific tools is displayed. The buttons in this toolbar represent the types of controls that can be inserted into the dialog. The user clicks the desired button, then draws a frame with the mouse at the position to insert the corresponding control type.

    The following three buttons in the dialog tools window do not represent controls:

    Select.png The Select button at the lower right of the dialog tools window switches the mouse cursor to selection mode. In this mode, controls are selected by clicking the control with the cursor. If the Shift key is held down simultaneously, the selection is extended by each control the user clicks. Controls can also be selected by drawing a rubber band frame with the mouse. All controls that are completely inside the frame will be selected. To select the dialog frame the user clicks its border or includes it in a selection frame completely.
    ActivateTestMode.png The Activate Test Mode button switches on the test mode for dialogs. In this mode, the dialog is displayed as if it was a Basic script (see Programming Dialogs and Dialog Controls). However, the macros assigned to the controls do not work in this mode. They are there to help the user design the look and feel of the dialog.
    ControlProperties.png The Properties button at the lower left of the dialog tools window opens and closes the Properties dialog. This dialog is used to edit all properties of the selected control(s). The next illustration shows the Properties dialog for a selected button control.
    ManageLanguageIcon.png The Manage Language button (available since OpenOffice.org 2.2.0 opens the Manage User Interface Languages dialog allowing to manage the localization of dialogs. All details concerning Dialog localization are described in Dialog Localization.
    The Properties dialog for a command button

    The illustration above shows that the dialog tool window can be pulled from the main toolbar by dragging the window at its caption bar after opening it.

    The Properties dialog has two tabs. The General tab, visible in Illustration 12.26, contains a list of properties. Their values are represented by a control. For most properties this is a list box, such as color and enum types, or an edit field, such as numeric or text properties. For more complex properties, such as fonts or colors, an additional ellipsis button opens another type of dialog, for example, to select a font. When the user changes a property value in an edit field this value is not applied to the control until the edit field has lost the focus. This is forced with the tab key. Alternatively, the user can commit a change by pressing the Enter key.

    The Events tab page displays the macros assigned to the events supported by the selected control:

    The Events tab page of the Properties dialog

    In the example above, a macro is assigned to the Key pressed event: When this event occurs, the displayed Sub doNothing in Module2 of the application Basic library Standard is called. The events that are available depend on the type of control selected.

    To change the event assignment the user has to click one of the ellipsis buttons to open the Assign Action dialog displayed in the illustration below.

    Assign Action Dialog

    The list box titled Event displays the same information as the Events tab of the Properties dialog. The Assign Action dialog is always the same, that is only the selected event in its Event list changes according to the ellipsis button the user selected on the Events tab of the Properties dialog.

    To assign a macro to an event, the user needs to click on the Macro ... button. This opens the Macro Selector dialog which allows the user to select a macro from the library hierarchy. Clicking OK in the Macro Selector assigns the selected macro to the event. If another macro is already assigned to an event, this macro is replaced. If no Sub is selected, the OK button is disabled.

    If the dialog is stored in a document, the library hierarchy displayed in the Macro Selector dialog contains the application library containers and the library container of the document. If the dialog belongs to an application dialog library, document macros are not displayed since they cannot be assigned to the controls of application dialogs. This is because it cannot be guaranteed that the document will be loaded when the application dialog event is fired.

    The Remove button is enabled if an event with an assigned macro is selected. Clicking this button removes the macro from the event, therefore the event will have no macro binding.

    The list box below the Remove button is used to select different macro languages. Currently, only LibreOffice Basic is available.

    The OK button closes the Assign Action dialog, and applies all event assignments and removals to the control. The changes are reflected on the Events tab of the Properties dialog.

    The Cancel button also closes the Assign Action dialog, but all assignment and removal operations are discarded.

    As previously explained, it is also possible to select several controls simultaneously. The next picture shows the situation if the user selects both CommandButton1 and CheckBox1. For the Properties dialog such a multi selection has some important effects.

    Properties dialog for multi selection

    Here the caption of the Properties contains the string Multiselection to point out the special situation. The two important differences compared to the single selection situation are:

    • The displayed properties are an intersection of the properties of all the selected controls, that is, the property is only displayed if all the selected controls support that property. A property value is only displayed if the value is the same for all selected controls. All selected controls are effected when a value is changed by the user. Values that are not the same for all controls can be set with the effect that the specified value applies to all controls in the selection.
    • A multi-selection Properties dialog does not have an Events tab. Events can only be specified for single controls.

    Assigning Macros to GUI Events

    The functionality to assign macros to control events in the dialog editor was discussed earlier. There is also a general functionality to assign macros or other actions to events. This functionality can be accessed through the Customize dialog that is opened using Tools – Customize or by clicking the Assign button in the Macro dialog. In this section, only the assignment of macros is discussed. For more information about this dialog, refer to the LibreOffice documentation.

    The next illustration shows the Menu tab of the Customize dialog

    Configuration dialog for Menu

    The illustration above shows how a macro is assigned to a new menu item. The Menu and Menu Content list boxes can be used to navigate the LibreOffice menu hierarchy. Clicking the Add... button opens the Add Commands dialog. The Category list box in the Add Commands dialog contains entries for built-in LibreOffice functions, and a OpenOffice Macros entry that represents the hierarchy of LibreOffice macros. When an entry is selected in the Category list box, any commands or macros it contains are displayed in the Commands list box on the right.

    Clicking the Add button in the Add Commands dialog adds the selected command or macro to a menu.

    The other buttons in the Menus tab of the Customize dialog are as follows:

    • The New button creates a new top level menu
    • The Menu button has commands for moving, renaming and deleting top level menus
    • The Modify button has commands for adding submenus and separators, and renaming and deleting menu items.
    • The arrow buttons change the position of a menu item.
    • The Reset button restores the default menu configuration.

    The next illustration shows the Events tab of the Customize dialog:

    Configuration dialog for Events

    On this tab, macros can be assigned to general events in LibreOffice. The events are listed in the list box titled Event. The Assign button opens the Macro Selector from which the user can select macros to assign to events. The Remove button removes the assigned macro from the selected event.

    In the Keyboard tab macros are accessed in Category and Function list boxes, then assigned to a shortcut key that can be specified in the Shortcut keys list box. There are also Load, Save, and Reset buttons for loading, storing and resetting keyboard configurations.

    The Keyboard tab contains OpenOffice and Document radio buttons which control the scope for which keyboard assignments are made.

    Dialog Localization

    Beginning with OpenOffice.org 2.2.0 it is possible to localize dialogs created in the Dialog Editor. The localization always refers to complete Dialog Libraries, not to single dialogs. A Dialog Library's default state is “Not localized”. In this state dialogs behave and are stored in the same way as before the localization feature was available.

    The entry point for localizing a Dialog Library is the Manage User Interface Languages dialog that can be opened by clicking the Manage Language button in the dialog tool window. The following illustration shows the dialog editor with an opened Manage User Interface Languages dialog.

    Dialog Editor with Manage User Interface Languages dialog

    Initially no language is defined, so the Present Languages list has no entry. The dialog captions shows that the localization refers to the complete library Standard. To enable localization for this library the Add... button has to be used. It opens another dialog allowing to choose the first language to be supported (see the next illustration). The currently active UI language is preselected.

    Set Default User Interface Language dialog
    Note pin.svg

    Note:
    The comment on this dialog is important. By choosing the first language all localizable dialog/control strings are replaced by Resource IDs (see Technical Background) referencing the strings in a String Resource component managing strings for different languages. The strings are not copied but moved into the String Resource. After localizing a dialog the strings only exist there and not as dialog/control properties anymore.

    After choosing a language and clicking the OK button this language becomes the only entry in the Present Languages list of the Manage User Interface Languages dialog:

    Manage User Interface Languages dialog with one language

    The first language also becomes the first default language. As stated in the comment on the dialog itself the Default language is relevant in two situations.

    • If a dialog does not support the language that is required the strings for the default language will be displayed. Example: A dialog supports English and French with English being the Default Language. If this dialog is used with German being the Office's user interface language, English strings will be displayed.
    • When a new language is added, all strings are taken from the default language. Example: A button label is “Thanks” for English and “Merci” for French with English being the default language. When adding German as another language the label initially will also be “Thanks”. The idea behind this behavior is that a user creating a localized dialog will usually like to take his own mother language or a common language like English as reference for translating to any other language.

    Now - or any time later - other languages can be added by again clicking the Add... button. This time a slightly different dialog is used:

    Add User Interface Languages dialog

    It allows to choose more than one language. As also described in the comment on the dialog the strings for the new languages will be copied from the current default language. After checking one or more languages and clicking the OK button these languages also become entries in the Present Languages list of the Manage User Interface Languages dialog:

    Manage User Interface Languages dialog with three languages

    The default language can be changed by selecting another language and clicking the Default button. One or more languages can be deleted by selecting them and clicking the Delete button. As deleting a language also deletes all strings associated with this language this action will only be completed after a corresponding warning message has been acknowledged by the user. If the Default Language is deleted the first of the remaining languages will become Default Language.

    If all languages are deleted the Library will return to the “not localized” state. The Resource IDs (see Technical Background) stored in the localizable dialog/control properties will be replaced by the corresponding strings assigned to the last Default Language.

    If a Dialog Library is localized an additional Language toolbar is visible. It allows to select the current language as shown in the next illustration. Besides the List Box containing the Languages another Manage Language button is placed allowing to open the Manage User Interface Languages dialog also from the Language toolbar.

    Dialog Editor with Locale Toolbar

    All localizable dialog/control strings are displayed for this current language. So the button label in the illustration is “English” if English is selected as current language, but it can be different for the other languages. If a localized property is changed using the Properties Dialog this change also is only related to the current language. The next illustration shows how the dialog could look after switching the current language to French.

    Dialog Editor with French as current locale

    The following list shows which dialog/control properties are localizable at all:

    • Label (Button, Check Box, Option Button)
    • Text (Text Box, Combo Box)
    • StringItemList (List Box, Combo Box)
    • Title (Dialog)
    • CurrencySymbol (Currency Field)
    • HelpText (all controls)

    Currently, the localization is limited to strings that are visible in the dialog or that could become visible in another context like the help text.

    Technical Background

    This section provides an overview of how the Dialog Localization feature works internally and how the resources are stored. In case of a localized Dialog Library the localized properties do not contain strings but Resource IDs referring to a String Resource table. Example:

    Dialog XML snippet, not localized:

    <dlg:window ... dlg:title="My Dialog">
    ...
    <dlg:button ... dlg:value="My Label"/>

    Dialog XML snippet, localized:

    <dlg:window ... dlg:title="&amp;1.Dialog1.Title">
    ...
    <dlg:button ... dlg:value="&amp;3.Dialog1.CommandButton1.Label"/>

    "&" is the XML encoding for the & character. This character is used as escape character marking the string as localized. The pure Resource ID is 1.Dialog1.Title respectively 3.Dialog1.CommandButton1.Label.

    The strings referenced by the Resource IDs are stored in files meeting the format of Java properties files, e.g. described in https://docs.oracle.com/javase/9/docs/api/java/util/Properties.html. In the Library's folder one of these files is stored for each language following a special naming scheme. For the languages used in the example above the following files are stored in the Dialog Library's folder (both for Application based libraries stored in the file system and for Document based libraries stored in a document's package file):

     Dialog1.xdl                     // Dialog XML description
     DialogStrings_en_US.properties  // English (USA) properties file
     DialogStrings_et_EE.properties  // Estonian properties file
     DialogStrings_fr_FR.properties  // French properties file
     DialogStrings_en_US.default     // Empty file marking English (USA) as default language
    

    Each of these files contain all strings for the corresponding language using the Resource IDs as keys. The French properties file for the dialog shown in the last illustration looks like this:

     # Strings for Dialog Library Standard
     0.Dialog1.HelpText=1.Dialog
     1.Title=French Dialog
     2.Dialog1.CommandButton1.HelpText=
     3.Dialog1.CommandButton1.Label=French
     4.Dialog1.CheckBox1.HelpText=
     5.Dialog1.CheckBox1.Label=French Box1
     6.Dialog1.CheckBox2.HelpText=
     7.Dialog1.CheckBox2.Label=French Box2
     8.Dialog1.ListBox1.HelpText=
     9.ListBox1.StringItemList=French List Entry1
     10.ListBox1.StringItemList=French List Entry2
     11.ListBox1.StringItemList=French List Entry3
    

    The IDs start with a numeric part that is unique for the complete library. The textual part following then contains the Dialog, Control and Property name the Resource ID refers to. The numeric ID alone would be unique but the textual part makes it easier to associate Resource IDs and controls when resource properties files should be edited manually. When the dialog or controls are renamed the Resource IDs are renamed accordingly.

    The UNO API used for managing the String Resource is placed in <idl>com.sun.star.resource</idl>. Each Dialog Library supports <idl>com.sun.star.resource.XStringResourceSupplier</idl>, giving access to a <idl>com.sun.star.resource.StringResource</idl> component. This component supports <idl>com.sun.star.resource.XStringResourceResolver</idl>, allowing to resolve strings using Resource IDs as keys and <idl>com.sun.star.resource.XStringResourceManager</idl>, allowing to add and remove strings and languages.

    In case of an Application Dialog Library the StringResource supports <idl>com.sun.star.resource.StringResourceWithLocation</idl> allowing to read/write the properties files from/to the file system. In case of a Document Dialog Library the StringResource supports <idl>com.sun.star.resource.StringResourceWithStorage</idl> allowing to read/write the properties files from/to the document's package file.

    Further details are described in the IDL documentation.

    Features of LibreOffice Basic

    This section provides a general description of the Basic programming language integrated in LibreOffice.

    Functional Range Overview

    This section outlines the functionality provided by LibreOffice Basic. The available runtime library functions are also described. The functionality is based upon the Basic online help integrated in LibreOffice, but limited to particular functions. Use the Basic online help to obtain further information about the complete Basic functionality.

    Apart from the LibreOffice API, LibreOffice Basic is compatible to Visual Basic.

    Screen I/O Functions

    Basic provides statements and functions to display information on the screen or to get information from the user:

    • The Print statement displays strings or numeric expressions in a dialog. Multiple expressions are separated by commas that result in a tab distance between the expressions, or semicolons that result in a space between the expressions. For example:

    e = 2.718
    Print e                  ' displays "2.718"
    Print "e =" ; e          ' displays "e = 2.718"
    Print "e =" , e          ' displays "e = 2.718"

    • The MsgBox function displays a dialog box containing a message. Additionally, the caption of the dialog, buttons, such as OK, Cancel, Yes and No, and icons, such as question mark and exclamation mark, that are to be displayed are specified. The result then can be evaluated. For example:

    ' display a message box with an exclamation mark and OK and Cancel buttons
    ret& = Msgbox ("Changes will be lost. Proceed?", 48 + 1, "Warning")
    
    ' show user's selection. 1 = OK, 2 = Cancel
    Print ret&

    • The InputBox function displays a prompt in a dialog where the user can input text. The input is assigned to a variable. For example:

    ' display a dialog with "Please enter a phrase:" and "Dear User" as caption
    ' the dialog contains an edit control and the text entered by the user
    ' is stored in UserText$ when the dialog is closed with OK. Cancel returns ""
    UserText$ = InputBox( "Please enter a phrase:", "Dear User" )

    File I/O

    LibreOffice Basic has a complete set of statements and runtime functions to access the operating system's file system that are compatible to Visual Basic. For platform independence, the ability to handle file names in file:// URL notation has been added.

    It is not recommended to use this classic Basic file interface in the UNO context, because many interfaces in the LibreOffice API expect file I/O specific parameters whose types, for example, <idl>com.sun.star.io.XInputStream</idl> are not compatible with the classic Basic file API.

    Tip.svg

    Tip:
    The module UCB of Basic library Tools of the container OpenOffice Macros shows some examples of file I/O using the API :

    • Function ReadDirectories( )
    • Sub SaveDataToFile( )
    • Function LoadDataFromFile( )
    • Function CreateFolder( )


    For programming, the file I/O in LibreOffice API context with the service <idl>com.sun.star.ucb.SimpleFileAccess</idl> should be used. This service supports the interface <idl>com.sun.star.ucb.XSimpleFileAccess2</idl>, including the main interface <idl>com.sun.star.ucb.XSimpleFileAccess</idl> that provides fundamental methods to access the file system. The methods are explained in detail in the corresponding interface documentation. The following list provides an overview about the operations supported by this service:

    • copy, move and remove files and folders (methods copy(), move(), kill())
    • prompt for information about files and folders (methods isFolder(), isReadOnly(), getSize(), getContentType(), getDateTimeModified(), exists())
    • open or create files (openFileRead(), openFileWrite(), openFileReadWrite()). These functions return objects that support the corresponding stream interfaces <idl>com.sun.star.io.XInputStream</idl>, <idl>com.sun.star.io.XOutputStream</idl> and <idl>com.sun.star.io.XStream</idl>. These interfaces are used to read and write files. The XSimpleFileAccess2 does not have methods of its own for these operations. Additionally, these interfaces are often necessary as parameters to access methods of several other interfaces. The opened files have to be closed by calling the appropriate methods <idlm>com.sun.star.io.XInputStream:closeInput</idlm>() or <idlm>com.sun.star.io.XOutputStream:closeOutput</idlm>().
    • The XSimpleFileAccess2 also does not have methods to ask for or set the position within a file stream. This is done by calling methods of the <idl>com.sun.star.io.XSeekable</idl> interface that is supported by the objects returned by the openXXX() methods.

    Two more services are instantiated at the global service manager that extends the service <idl>com.sun.star.ucb.SimpleFileAccess</idl> by functionality specific to text files:

    • The service <idl>com.sun.star.io.TextInputStream</idl> supporting <idl>com.sun.star.io.XTextInputStream</idl> and <idl>com.sun.star.io.XActiveDataSink</idl>
    • The service is initialized by passing an object supporting XInputStream to the <idlm>com.sun.star.io.XActiveDataSink:setInputStream</idlm>() method, for example, an object returned by <idlm>com.sun.star.ucb.XSimpleFileAccess:openFileRead</idlm>().
    Then the method <idlm>com.sun.star.io.XTextInputStream:readLine</idlm>() and <idlm>com.sun.star.io.XTextInputStream:readString</idlm>() are used to read text from the input stream/file. The method <idlm>com.sun.star.io.XTextInputStream:isEOF</idlm>() is used to check for if the end of the file is reached. The <idlm>com.sun.star.io.XTextInputStream:setEncoding</idlm>() sets a text encoding where UTF-8 is the default.
    • The service <idl>com.sun.star.io.TextOutputStream</idl> supporting <idl>com.sun.star.io.XTextOutputStream</idl> and <idl>com.sun.star.io.XActiveDataSource</idl>
    • The service is initialized by passing an object supporting XOutputStream to the <idlm>com.sun.star.io.XActiveDataSource:setOutputStream</idlm>() method, for example, an object returned by <idlm>com.sun.star.ucb.XSimpleFileAccess:openFileWrite</idlm>().

    Then the method <idlm>com.sun.star.io.XTextOutputStream:writeString</idlm>() is used to write text to the output stream.

    Date and Time Functions

    LibreOffice Basic supports several Visual Basic compatible statements and functions to perform date and time calculations. The functions are DateSerial, DateValue, Day, Month, WeekDay, Year, Hour, Now, Second, TimeSerial, TimeValue, Date, Time, and Timer.

    The function Date returns the current system date as a string and the function Time returns the current system time as a string. The other functions are not explained.

    In the UNO/toolkit controls context there are two other functions. The date field control method <idlm>com.sun.star.awt.XDateField:setDate</idlm>() expects the date to be passed as a long value in a special ISO format and the <idlm>com.sun.star.awt.XDateField:getDate</idlm>() returns the date in this format.

    The Basic runtime function CDateToIso converts a date from the internal Basic date format to the required ISO date format. Since the string date format returned by the Date function is converted to the internal Basic date format automatically, Date can be used directly as an input parameter for CDateToIso:

    IsoDate = CDateToIso(Date)
    oTextField.setDate(IsoDate)

    The runtime function CDateFromIso represents the reverse operation and converts a date from the ISO date format to the internal Basic date format.

    Dim aDate as date
    aDate = CDateFromIso(IsoDate)

    Please see also Programming Dialogs and Dialog Controls in this context.

    Numeric Functions

    LibreOffice Basic supports standard numeric functions, such as:

    • Cos calculating the cosine of an angle
    • Sin calculating the sine of an angle
    • Tan calculating the tangent of an angle
    • Atn calculating the arctangent of a numeric value
    • Exp calculating the base of the natural logarithm (e = 2.718282) raised to a power
    • Log calculating the natural logarithm of a number
    • Sqr calculating the square root of a numeric value
    • Abs calculating the absolute value of a numeric value
    • Sgn returning -1 if the passed numeric value is negative, 1 if it is positive, 0 if it is zero.

    String Functions

    LibreOffice Basic supports several runtime functions for string manipulation. Some of the functions are explained briefly in the following:

    • Asc returns the Unicode value of the first character of its string parameter.
    • Chr returns a string containing the character that is specified by the ASCII or Unicode value passed to the function. This function is used to represent characters, such as the carriage return code (Chr(13)), that cannot be written in the "" notation. This is not necessary for the " character, which can be included in a string literal by simply doubling it, eg. s = "This string has ""embedded"" quotes"
    • Str converts a numeric expression to a string in a locale-independent manner (contrary to the CStr function).
    • Val converts a string to a numeric value.
    • LCase converts all letters in a string to lowercase. Only uppercase letters within the string are converted. All lowercase letters and nonletter characters remain unchanged.
    • UCase converts characters in a string to uppercase. Only lowercase letters in a string are affected. Uppercase letters and all other characters remain unchanged.
    • Left returns the leftmost “n” characters of a string expression.
    • Mid returns the specified portion of a string expression.
    • Right returns the rightmost "n" characters of a string expression.
    • Trim removes all leading and trailing spaces of a string expression.

    All these functions are fully compatible with VBA and all functions returning a string can be specified with a trailing $ like Mid$.

    Specific UNO Functions

    The UNO specific runtime functions CreateUnoListener, CreateUnoService, GetProcessServiceManager, HasUnoInterfaces, IsUnoStruct, EqualUnoObjects are described in LibreOffice Basic.

    Accessing the UNO API

    In LibreOffice Basic, the interaction between Basic and UNO is described on an elementary level. This section describes the interface between Basic and the UNO API at the level of the LibreOffice application.

    This is realized by two predefined Basic properties:

    • StarDesktop
    • ThisComponent

    The property StarDesktop gives access to the global LibreOffice application API while the property ThisComponent accesses the document related API.

    StarDesktop

    The property StarDesktop is a shortcut for the service <idl>com.sun.star.frame.Desktop</idl>.

    Example:

    MsgBox StarDesktop.Dbg_SupportedInterfaces
    
    ' is the same as
    
    Dim oDesktop
    oDesktop = CreateUnoService( "com.sun.star.frame.Desktop" )
    MsgBox oDesktop.Dbg_SupportedInterfaces

    The displayed message box differs slightly because Dbg_SupportedInterfaces displays "StarDesktop" as an object type of the desktop object in the first case and "com.sun.star.frame.Desktop" in the second. But the two objects are the same.

    ThisComponent

    The property ThisComponent is used from document Basic, where it represents the document the Basic belongs to. The type of object accessed by ThisComponent depends on the document type. The following example shows the differences.

    Basic module in a LibreOffice document:

    Sub Main
        MsgBox ThisComponent.Dbg_SupportedInterfaces
    End Sub

    The execution of this Basic routine shows different results for a Text, Spreadsheet and Presentation document. Depending on the document type, a different set of interfaces are supported by the object. A portion of the interfaces are common to all these document types representing the general functionality that documents of any type offer. In particular, all LibreOffice documents support the <idl>com.sun.star.document.OfficeDocument</idl> service, including the interfaces <idl>com.sun.star.frame.XStorable</idl> and <idl>com.sun.star.view.XPrintable</idl>. Another interface is <idl>com.sun.star.frame.XModel</idl>.

    The following list shows the interfaces supported by all document types:

    • <idl>com.sun.star.beans.XPropertySet</idl>
    • <idl>com.sun.star.container.XChild</idl>
    • <idl>com.sun.star.document.XDocumentInfoSupplier</idl>
    • <idl>com.sun.star.document.XEventBroadcaster</idl>
    • <idl>com.sun.star.document.XViewDataSupplier</idl>
    • <idl>com.sun.star.document.XEventsSupplier</idl>
    • <idl>com.sun.star.document.XLinkTargetSupplier</idl>
    • <idl>com.sun.star.frame.XModel</idl>
    • <idl>com.sun.star.frame.XStorable</idl>
    • <idl>com.sun.star.lang.XServiceInfo</idl>
    • <idl>com.sun.star.lang.XMultiServiceFactory</idl>
    • <idl>com.sun.star.lang.XEventListener</idl>
    • <idl>com.sun.star.style.XStyleFamiliesSupplier</idl>
    • <idl>com.sun.star.util.XModifiable</idl>
    • <idl>com.sun.star.view.XPrintable</idl>

    For more information about the functionality of these interfaces, see Frame-Controller-Model Paradigm in LibreOffice. This section also goes into detail about the general document API.

    In addition to the common services or interfaces, each document type supports specific services or interfaces. The following list outlines the supported services and important interfaces:

    A Text document supports:

    • The service <idl>com.sun.star.text.TextDocument</idl> supports the interface <idl>com.sun.star.text.XTextDocument</idl>.
    • Several interfaces, especially from the <idlmodule>com.sun.star.text</idlmodule> package.

    A Spreadsheet document supports:

    • The service <idl>com.sun.star.sheet.SpreadsheetDocument</idl>,
    • The service <idl>com.sun.star.sheet.SpreadsheetDocumentSettings</idl>.
    • Several other interfaces, especially from the <idlmodule>com.sun.star.sheet</idlmodule> package.

    Presentation and Drawing documents support:

    • The service <idl>com.sun.star.drawing.DrawingDocument</idl>.
    • Several other interfaces, especially from the <idlmodule>com.sun.star.drawing</idlmodule> package.

    The usage of these services and interfaces is explained in the document type specific chapters Text Documents, Spreadsheet Documents and Drawing Documents and Presentation Documents.

    As previously mentioned, ThisComponent is used from document Basic, but it is also possible to use it from application Basic. In an application wide Basic module, ThisComponent is identical to the current component that can also be accessed through StarDesktop.CurrentComponent. The only difference between the two is that if the BasicIDE is active, StarDesktop.CurrentComponent refers to the BasicIDE itself while ThisComponent always refers to the component that was active before the BasicIDE became the top window.

    ThisDatabaseDocument

    The property ThisDatabaseDocument, introduced since OpenOffice.org 3.1, is only used from a Basic code which is embedded in a Base document. It refers to the Base document model.

    Typically, when a macro is started by an event from a Form of the Base document, ThisDatabaseDocument represents the Base document, whereas ThisComponent refers to the Form document.

    Special Behavior of LibreOffice Basic

    Threading and rescheduling of LibreOffice Basic differs from other languages which must be taken into consideration.

    Threads

    LibreOffice Basic does not support threads:

    • In situations it may be necessary to create new threads to access UNO components in a special way. This is not possible in LibreOffice Basic.
    • LibreOffice Basic is unable to control threads. If two threads use the Basic runtime system simultaneously, the result will be undefined results or even a crash. Please take precautions.

    Rescheduling

    The LibreOffice Basic runtime system reschedules regularly. It allows system messages to be dispatched continuously that have been sent to the LibreOffice process during the runtime of a Basic module. This is necessary to allow repainting operations, and access to controls and menus during the runtime of a Basic script as Basic runs in the LibreOffice main thread. Otherwise, it would not be possible to stop a running Basic script by clicking the corresponding button on the toolbar.

    This behavior has an important consequence. Any system message, for example, clicking a push button control, can result in a callback into Basic if an corresponding event is specified. The Basic programmer must be aware of the fact that this can take place at any point of time when a script is running.

    The following example shows how this effects the state of the Basic runtime system:

    Dim EndLoop As Boolean
    Dim AllowBreak As Boolean
    
    ' Main sub, the execution starts here
        Sub Main
        ' Initialize flags
        EndLoop = FALSE
        AllowBreak = FALSE
    
        Macro1' calls sub Macro1
    End Sub
    
    ' Sub called by main
    Sub Macro1
        Dim a
        While Not EndLoop
            ' Toggle flags permanently
            AllowBreak = TRUE
            AllowBreak = FALSE
        Wend
        Print "Ready!"
    End Sub
    
    ' Sub assigned to a bush button in a writer document
    Sub Break
    If AllowBreak = TRUE Then
        EndLoop = TRUE
        EndIf
    End Sub

    When Sub Main in this Basic module is executed, the two Boolean variables EndLoop and AllowBreak are initialized. Then Sub Macro1 is called where the execution runs into a loop. The loop is executed until the EndLoop flag is set to TRUE. This is done in Sub Break that is assigned to a push button in a writer document, but the EndLoop flag can only be set to TRUE if the AllowBreak flag is also TRUE. This flag is permanently toggled in the loop in Sub Macro1.

    The program execution may or may not be stopped if the push button is clicked. It depends on the point of time the push button is clicked. If the Basic runtime system has just executed the AllowBreak = TRUE statement, the execution is stopped because the If condition in Sub Break is TRUE and the EndLoop flag can be set to TRUE. If the push button is clicked when the AllowBreak variable is FALSE, the execution is not stopped. The Basic runtime system reschedules permanently, therefore it is unpredictable. This is an example to show what problems may result from the Basic rescheduling mechanism.

    Callbacks to Basic that result from rescheduling have the same effect as if the Sub specified in the event had been called directly from the position in the Basic code that is executed in the moment the rescheduling action leading to the callback takes place. In this example, the Basic call stack looks like this if a breakpoint is placed in the Sub Break:

     Basic         Native code
    
     0: Break  <---  Callback due to push button event
     1: Macro1 --->  Reschedule()
     2: Main
    

    With the call to the native Reschedule method, the Basic runtime system is left and reentered when the push button events in a Callback to Basic. On the Basic stack this looks like a direct call from Sub Macro1 to Sub Break.

    A similar situation occurs when a program raises a dialog using the execute method of the dialog object returned by CreateUnoDialog(). See Programming Dialogs and Dialog Controls. In this case, the Basic runtime system does not reschedule, but messages are processed by the dialog's message loop that also result in callbacks to Basic. When the Basic runtime system is called back due to an event at a dialog control, the resulting Basic stack looks analogous. For example:

    Sub Main
        Dim oDialog
        oDialog = CreateUnoDialog( ... )
        oDialog.execute()
    End Sub
    
    Sub DoIt
        ...
    End Sub

    If Sub Doit is specified to be executed if an event occurs for one of the dialog controls, the Basic call stack looks like this if a breakpoint is placed in Sub DoIt:

     Basic        Native code
    
     0: DoIt <--- Callback due to control event
     1: Main ---> execute() ---> Reschedule()
    

    There is also a difference to the rescheduling done directly by the Basic runtime system. The rescheduling done by the dialog's message loop can not result in unpredictable behavior, because the Basic runtime system has called the dialog's execute method and waits for its return. It is in a well-defined state.

    Advanced Library Organization

    Basic source code and Dialogs are organized in libraries. This section describes the structure and usage of the library system.

    General Structure

    The library system that is used to store Basic source code modules and Dialogs has three levels:

    Library container

    • The library container represents the top level of the library hierarchy containing libraries. The libraries inside a library container are accessed by name.

    Library

    • A library contains elements that logically belong together, for example, several Basic modules that form a program or a set of related dialogs together.

    Library elements

    • Library elements are Basic source code modules or dialogs. The elements represent the lowest level in the library hierarchy. For Basic source code modules, the element type is string. Dialogs are represented by the interface <idl>com.sun.star.io.XInputStreamProvider</idl> that provides access to the XML data describing the dialog.

    The hierarchy is separated for Basic source code and dialogs, that is, a Basic library container only contains Basic libraries containing Basic source code modules and a dialog library container only contains dialog libraries containing dialogs.

    Basic source code and dialogs are stored globally for the whole office application and locally in documents. For the application, there is one Basic library container and one dialog library container. Every document has one Basic library container and one dialog library container as well. By including the application or document level, the library system actually has four levels. Illustration 1: Sample module structure depicts this structure.

    As shown in the library hierarchy for Document 1, the Basic and dialog library containers do not have the same structure. The Basic library container has a library named Library1 and the dialog library container has a library named Library2. The library containers are separated for Basic and dialogs in the API.

    It is not recommended to create a structure as described above because the library and dialog containers are not separated in the GUI, for example, in the LibreOffice Basic Macros dialog. When a user creates or deletes a new library in the LibreOffice Basic Macro Organizer dialog , the library is created or deleted in the Basic and the dialog library containers.

    Simple module structure

    Accessing Libraries from Basic

    Library Container Properties in Basic

    Currently, the library system is implemented using UNO interfaces, not as a UNO service. Therefore, the library system cannot be accessed by instantiating an UNO service. The library system has to be accessed directly from Basic using the built-in properties BasicLibraries and DialogLibraries.

    The BasicLibraries property refers to the Basic library container that belongs to the library container that the BasicLibraries property is accessed. In an application-wide Basic module, the property BasicLibraries accesses the application Basic library container and in a document Basic module, the property BasicLibraries contains the document Basic library container. The same applies to the DialogLibraries property.

    Loading Libraries

    Initially, most Basic libraries are not loaded. All the libraries in the application library container are known after starting LibreOffice, and all the library elements in a document are known when it is loaded, most of them are disabled until they are loaded explicitly. This mechanism saves time during the Basic initialization. When a Basic library is initialized, the source code modules are inserted into the Basic engine and compiled. If there are many libraries with big modules, it is tim consuming, especially if the libraries are not required.

    The exception to this is that every library container contains a library named "Standard" that is always loaded. This library is used as a standard location for Basic programs and dialogs that do not need a complex structure. All other libraries have to be loaded explicitly. For example:

    When Library1, Module1 looks like

    Sub doSomething
        MsgBox "doSomething"
    End Sub

    the following code in library Standard, Module1

    Sub Main
        doSomething()
    End Sub

    fails, unless the user loaded Library1 before using the Tools - Macro dialog. A runtime error "Property or method not found" occurs. To avoid this, load library Library1 before calling doSomething():

    Sub Main
        BasicLibraries.loadLibrary( "Library1" )
        doSomething()
    End Sub

    Accordingly in the dialog container, all the libraries besides the Standard library have to be loaded before the dialogs inside the library can be accessed. For example:

    Sub Main
        ' If this line was missing the following code would fail
        DialogLibraries.loadLibrary( "Library1" )
    
        ' Code to instantiate and display a dialog
        ' Details will be explained in a later chapter
        oDlg = createUnoDialog( DialogLibraries.Library1.Dialog1 )
        oDlg.execute()
    End Sub

    The code to instantiate and display the dialog is described in Programming Dialogs and Dialog Controls. The library representing DialogLibraries.Library1.Dialog1 is only valid once Library1 has been loaded.

    The properties BasicLibraries and DialogLibraries refer to the container that includes the Basic source accessing these properties. Therefore in a document module Basic the properties BasicLibraries and DialogLibraries refer to the Basic and Dialog library container of the document. In most cases, libraries in the document have to be loaded. In other cases it might be necessary to access application-wide libraries from document Basic. This can be done using the GlobalScope property. The GlobalScope property represents the root scope of the application Basic, therefore the application library containers can be accessed as properties of GlobalScope.

    Example module in a Document Basic in library Standard:

    Sub Main
        ' This code loads Library1 of the
    ...' Document Basic library container
        BasicLibraries.loadLibrary( "Library1" )
    
        ' This code loads Library1 of the
    ...' Document dialog library container
        DialogLibraries.loadLibrary( "Library1" )
    
        ' This code loads Library1 of the
    ...' Application Basic library container
        GlobalScope.BasicLibraries.loadLibrary( "Library1" )
    
        ' This code loads Library1 of the
    ...' Application dialog library container
        GlobalScope.DialogLibraries.loadLibrary( "Library1" )
    
        ' This code displays the source code of the
    ...' Application Basic module Library1/Module1
        MsgBox GlobalScope.BasicLibraries.Library1.Module1
    End Sub

    Note pin.svg

    Note:
    Application library containers can be accessed from document-embedded Basic libraries using the GlobalScope property, for example, GlobalScope.BasicLibraries.Library1.

    Library Container API

    The BasicLibraries and DialogLibraries support <idl>com.sun.star.script.XLibraryContainer2</idl> that inherits from <idl>com.sun.star.script.XLibraryContainer</idl>, which is a <idl>com.sun.star.container.XNameContainer</idl>. Basic developers do not require the location of the interface to use a method, but a basic understanding is helpful when looking up the methods in the API reference.

    The XLibraryContainer2 handles existing library links and the write protection for libraries. It is also used to rename libraries:

    boolean isLibraryLink( [in] string Name)
    string getLibraryLinkURL( [in] string Name)
    boolean isLibraryReadOnly( [in] string Name)
    void setLibraryReadOnly( [in] string Name,
                            [in] boolean bReadOnly)
    void renameLibrary( [in] string Name, [in] string NewName)

    The XLibraryContainer creates and removes libraries and library links. Furthermore, it can test if a library has been loaded or, if necessary, load it.

    com::sun::star::script::XNameContainer createLibrary( [in] string Name)
    com::sun::star::script::XNameAccess createLibraryLink( [in] string Name,
                                    [in] string StorageURL, [in] boolean ReadOnly)
    void removeLibrary( [in] string Name)
    boolean isLibraryLoaded( [in] string Name)
    void loadLibrary( [in] string Name)

    The methods of XNameContainer access and manage the libraries in the container:

    void insertByName( [in] string name, [in] any element)
    void removeByName( [in] string name)
    any getByName( [in] string name)
    
    void replaceByName( [in] string name, [in] any element)
    
    sequence < string > getElementNames()
    boolean hasByName( [in] string name)
    type getElementType()
    boolean hasElements()

    These methods are accessed using the UNO API as described in LibreOffice Basic. Note however, these interfaces can only be used from LibreOffice Basic, not from other environments.

    Libraries can be added to library containers in two different ways:

    Creating a New Library

    Creating a new library is done using the createLibrary() method. A library created with this method belongs to the library container where createLibrary() has been called. The implementation of the library container is responsible for saving and loading this library. This functionality is not currently covered by the interfaces, therefore the implementation determines how and where this is done. The method createLibrary() returns a standard <idl>com.sun.star.container.XNameContainer</idl> interface to access the library elements and modify the library.
    Initially, such a library is empty and new library elements are inserted. It is also possible to protect a library from changes using the setLibraryReadOnly() method. In a read-only library, no elements can be inserted or removed, and the modules or dialogs inside cannot be modified in the BasicIDE. For additional information, see LibreOffice Basic IDE. Currently, the read-only status can only be changed through API.

    Creating a Link to an Existing Library

    Creating a link to an existing library is accomplished using the method createLibraryLink(). Its StorageURL parameter describes the location where the library .xlb file is stored. For additional information about this topic, see the section on Library File Structure). A library link is only referenced by the library container and is not owned, therefore the library container is not responsible for the location to store the library. This is only described by the StorageURL parameter.
    The ReadOnly parameter sets the read-only status of the library link. This status is independent of the read-only status of the linked library. A linked library is only modified when the library and link to the library are not read only. For example, this mechanism provides read-only access to a library located on a network drive without forcing the library to be read-only, thus the library can be modified easily by an authorized person without changing its read-only status.

    The following tables provides a brief overview about other methods supported by the library containers:

    Selected Methods of <idl>com.sun.star.script.XLibraryContainer2</idl>
    <idlm>com.sun.star.script.XLibraryContainer2:isLibraryLink</idlm>() boolean. Can be used to ask if a library was added to the library container as a link.
    <idlm>com.sun.star.script.XLibraryContainer2:getLibraryLinkURL</idlm>() string. Returns the StorageURL for a linked library. This corresponds to the StorageURL parameter of the createLibraryLink(...) method and is primarily meant to be displayed to the users through the graphical user interface.
    <idlm>com.sun.star.script.XLibraryContainer2:isLibraryReadOnly</idlm>() boolean. Retrieves the read-only status of a library. In case of a library link, the method returns only false, that is, the library can be modified, when the link or the linked library are not read only.
    <idlm>com.sun.star.script.XLibraryContainer:removeLibrary</idlm>() Assigns a new name to a library. If the library was added to the library container as a link, only the link is renamed.
    Selected Methods of <idl>com.sun.star.script.XLibraryContainer</idl>
    <idlm>com.sun.star.script.XLibraryContainer:loadLibrary</idlm>() void. Loads a library. This is explained in detail in section Advanced Library Organization
    <idlm>com.sun.star.script.XLibraryContainer:isLibraryLoaded</idlm>() boolean. Allows the user to find out if a library has already been loaded.
    <idlm>com.sun.star.script.XLibraryContainer:removeLibrary</idlm>() void. Removes the library from the library container. If the library was added to the library container as a link, only the link is removed, because the library addressed by the link is not considered to be owned by the library container.

    Variable Scopes

    Some aspects of scoping in Basic depend on the library structure. This section describes which variables declared in a Basic source code module are seen from what libraries or modules. Generally, only variables declared outside Subs are affected by this issue. Variables declared inside Subs are local to the Sub and not accessible from outside of the Sub. For example:

    Option Explicit      ' Forces declaration of variables
    
    Sub Main
        Dim a%
        a% = 42          ' Ok
        NotMain()
    End Sub
    
    Sub NotMain
        a% = 42          ' Runtime Error "Variable not defined"
    End Sub

    Variables can also be declared outside of Subs. Then their scope includes at least the module they are declared in. To declare variables outside the Subs, the commands Private, Public/Dim and Global are used.

    The Private command is used to declare variables that can only be used locally in a module. If the same variable is declared as Private in two different modules, they are used independently in each module. For example:

    Library Standard, Module1:

    Private x As Double
    
    Sub Main
        x = 47.11        ' Initialize x of Module1
        Module2_InitX    ' Initialize x of Module2
    
        MsgBox x         ' Displays the x of Module1
        Module2_ShowX    ' Displays the x of Module2
    End Sub

    Library Standard, Module2:

    Private x As Double
    
    Sub Module2_InitX
        x = 47.12        ' Initialize x of Module2
    End Sub
    
    Sub Module2_ShowX
        MsgBox x         ' Displays the x of Module2
    End Sub

    When Main in Module1 is executed, 47.11 is displayed (x of Module1) and then 47.12 (x of Module2).

    The Public and Dim commands declare variables that can also be accessed from outside the module. They are identical in this context. Variables declared with Public and Dim can be accessed from all modules that belong to the same library container. For example, based on the library structure shown in Illustration 12.39: Sample module structure, any variable declared with Public and Dim in the Application Basic Modules Standard/Module1, Standard/Module2, Library1/Module1, Library1/Module2 can also be accessed from all of these modules, therefore the library container represents the logical root scope.

    Warning.svg

    Warning:
    The names of the Basic modules (by default Module1, Module2, etc) are known by Basic on a public scope. You must avoid to have a variable or routine of public scope with the same name as one of the modules of the library.

    Example : Suppose that in your Basic library you have a module named PrintDoc. You must not declare, in any module of your library, a Public variable or a Public constant, or a Sub, or a Function, named PrintDoc.

    If you do have such collision, Basic may produce strange runtime error messages, or your Sub may not work.


    Programming Dialogs and Dialog Controls

    The dialogs and dialog controls are UNO components that provide a graphical user interface belonging to the module <idlmodule>com.sun.star.awt</idlmodule>. The Toolkit controls follow the Model-View-Controller (MVC) paradigm, which separates the component into three logical units, the model, view, and controller. The model represents the data and the low-level behavior of the component. It has no specific knowledge of its controllers or its views. The view manages the visual display of the state represented by the model. The controller manages the user interaction with the model.

    Note pin.svg

    Note:
    Note, that the Toolkit controls combine the view and the controller into one logical unit, which forms the user interface for the component.

    The following example of a text field illustrates the separation into model, view and controller.

    The model contains the data which describes the text field; for example, the text to be displayed, text color and maximum text length. The text field model is implemented by the <idl>com.sun.star.awt.UnoControlEditModel</idl> service that extends the <idl>com.sun.star.awt.UnoControlModel</idl> service. All aspects of the model are described as a set of properties which are accessible through the <idl>com.sun.star.beans.XPropertySet</idl> interface.

    The view is responsible for the display of the text field and its content. It is possible in general to have multiple views for the same model, but not for Toolkit dialogs. The view is notified about model changes; for example, changes to the text color property causes the text field to be repainted.

    The controller handles the user input provided through the keyboard and mouse. If the user changes the text in the text field, the controller updates the corresponding model property. In addition, the controller updates the view; for example, if the user presses the delete button on the keyboard, the marked text in the text field is deleted. A more detailed description of the MVC paradigm can be found in the chapter about Forms.

    The base for all the Toolkit controls is the <idl>com.sun.star.awt.UnoControl</idl> service that exports the following interfaces:

    • The <idl>com.sun.star.awt.XControl</idl> interface specifies control basics. For example, it gives access to the model, view and context of a control.
    • The <idl>com.sun.star.awt.XWindow</idl> interface specifies operations for a window component.
    • The <idl>com.sun.star.awt.XView</idl> interface provides methods for attaching an output device and drawing an object.

    Dialog Handling

    After you have designed a dialog, you can:

    • Show the dialog in your application
    • Obtain the dialog model
    • Use the dialog as a controls container
    • Modify the properties of the dialog
    • Add pages to the dialog

    Showing a Dialog

    After a dialog has been designed using the dialog editor, a developer wants to show the dialog from within the program code. The necessary steps are shown in the following example:

    Sub ShowDialog()
        Dim oLibContainer As Object, oLib As Object
        Dim oInputStreamProvider As Object
        Dim oDialog As Object
        Const sLibName = "Library1"
        Const sDialogName = "Dialog1"
        REM library container
        oLibContainer = DialogLibraries
        REM load the library
        oLibContainer.loadLibrary( sLibName )
        REM get library
        oLib = oLibContainer.getByName( sLibName )
        REM get input stream provider
        oInputStreamProvider = oLib.getByName( sDialogName )
        REM create dialog control
        oDialog = CreateUnoDialog( oInputStreamProvider )
        REM show the dialog
        oDialog.execute()
    End Sub

    The dialog control is created by calling the runtime function CreateUnoDialog() which takes an object as parameter that supports the <idl>com.sun.star.io.XInputStreamProvider</idl> interface. This object provides an input stream that represents an XML description of the dialog. The section Advanced Library Organization explains the accessing to the object inside the library hierarchy. The dialog control is shown by calling the execute() method of the <idl>com.sun.star.awt.XDialog</idl> interface. It can be closed by calling endExecute(), or by offering a Cancel or OK Button on the dialog. For additional information, see Programming Dialogs and Dialog Controls.

    Getting the Dialog Model

    If a developer wants to modify any properties of a dialog or a control, it is necessary to have access to the dialog model. From a dialog, the model can be obtained by the getModel method of the <idl>com.sun.star.awt.XControl</idl> interface

    oDialogModel = oDialog.getModel()

    or shorter

    oDialogModel = oDialog.Model

    Dialog as Control Container

    All controls belonging to a dialog are grouped together logically. This hierarchy concept is reflected by the fact that a dialog control is a container for other controls. The corresponding service <idl>com.sun.star.awt.UnoControlDialog</idl> therefore supports the <idl>com.sun.star.awt.XControlContainer</idl> interface that offers container functionality, namely access to its elements by name. Since in LibreOffice Basic, every method of every supported interface is called directly at the object without querying for the appropriate interface, a control with the name TextField1 can be obtained from a dialog object oDialog simply by:

    oControl = oDialog.getControl("TextField1")

    See LibreOffice Basic for additional information. The hierarchy between a dialog and its controls can be seen in the dialog model <idl>com.sun.star.awt.UnoControlDialogModel</idl>, which is a container for control models and therefore supports the <idl>com.sun.star.container.XNameContainer</idl> interface. A control model is obtained from a dialog model by:

    oDialogModel = oDialog.getModel()
    oControlModel = oDialogModel.getByName("TextField1")

    or shorter:

    oControlModel = oDialog.Model.TextField1

    The model of a control is also returned by the getModel() method of the control. In short notation:

    oControlModel = oControl.Model

    Dialog Properties

    It is possible to make some modifications before a dialog is shown. An example is to set the dialog title that is shown in the title bar of a dialog window. This can be achieved by setting the Title property at the dialog model through the <idl>com.sun.star.beans.XPropertySet</idl> interface:

    oDialogModel = oDialog.getModel()
    oDialogModel.setPropertyValue("Title", "My Title")

    or shorter

    oDialog.Model.Title = "My Title"

    Another approach is to use the setTitle method of the <idl>com.sun.star.awt.XDialog</idl> interface:

    oDialog.setTitle("My Title")

    or

    oDialog.Title = "My Title"

    Another property is the BackgroundColor property that sets a different background color for the dialog.

    Common Properties

    All Toolkit control models have a set of identical properties referred as the common properties. These are the properties PositionX, PositionY, Width, Height, Name, TabIndex, Step, and Tag.

    Note pin.svg

    Note:
    Note that a Toolkit control model has those common properties only if it belongs to a dialog model. This has also some consequences for the creation of dialogs and controls at runtime. See Creating Dialogs at Runtime.

    The PositionX, PositionY, Width, and Height properties change the position and size of a dialog, and control at runtime. When designing a dialog in the dialog editor, these properties are set automatically.

    The Name property is required, because all dialogs and controls are referenced by their name. In the dialog editor this name is created from the object name and a number, for example, TextField1.

    The TabIndex property defines the order of focusing a control in a dialog when pressing the tabulator key. The index of the first element has the value 0. In the dialog editor the TabIndex property is set automatically when inserting a control. The order can also be changed through the property browser. Take care when setting this property at runtime.

    The Tag property adds additional information to a control, such as a remark or number.

    The Step property is described in detail in the next section.

    Multi-Page Dialogs

    A dialog may have several pages that can be traversed by the user step by step. This feature is used in the LibreOffice autopilots. The dialog property Step defines which page of the dialog is active. At runtime the next page of a dialog is displayed by increasing the step value by 1.

    The Step property of a control defines the page of the dialog on which the control is visible. For example, if a control has a step value of 1, it is only visible on page 1 of the dialog. If the step value of the dialog is increased from 1 to 2, then all controls with a step value of 1 disappear and all controls with a step value of 2 become visible.

    The step value 0 has a special role. If a control has a step value of 0, the control is displayed on all dialog pages. If a dialog has a step value of 0, all controls of the dialog are displayed, regardless of the step value of the individual controls.

    Dialog Controls

    After you have created your dialog, you can add many different controls to it, for example buttons, images, labels, text, check boxes and scroll bars.

    Command Button

    The command button <idl>com.sun.star.awt.UnoControlButton</idl> allows the user to perform an action by clicking the button. Usually a button carries a label that is set through the Label property of the control model:

    oDialogModel = oDialog.getModel()
    oButtonModel = oDialogModel.getByName("CommandButton1")
    oButtonModel.setPropertyValue("Label", "My Label")

    or in short:

    oDialog.Model.CommandButton1.Label = "My Label"

    The label can also be set using the setLabel method of the <idl>com.sun.star.awt.XButton</idl> interface:

    oButton = oDialog.getControl("CommandButton1")
    oButton.setLabel("My Label")

    or in short:

    oButton.Label = "My Label"

    During runtime, you may want to enable or disable a button. This is achieved by setting the Enabled property to True or False. The PushButtonType property defines the default action of a button where 0 is the Default, 1 is OK, 2 is Cancel, and 3 is Help. If a button has a PushButtonType value of 2, it behaves like a cancel button, that is, pressing the button closes the dialog. In this case, the method execute() of the dialog returns with a value of 0. An OK button of PushButtonType 1 returns 1 on execute(). The property DefaultButton specifies that the command button is the default button on the dialog, that is, pressing the ENTER key chooses the button even if another control has the focus. The Tabstop property defines if a control can be reached with the TAB key.

    The command button has the feature, to display an image by setting the ImageURL property, which contains the path to the graphics file.

    oButtonModel = oDialog.Model.CommandButton1
    oButtonModel.ImageURL = "file:///D:/Office60/share/gallery/bullets/bluball.gif"
    oButtonModel.ImageAlign = 2

    All standard graphics formats are supported, such as .gif, .jpg, .tif, .wmf and .bmp. The property ImageAlign defines the alignment of the image inside the button where 0 is Left, 1 is Top, 2 is Right, and 3 is the Bottom. If the size of the image exceeds the size of the button, the image is not scaled automatically, but cut off. In this respect, the image control offers more functionality.

    Image Control

    If the user wants to display an image without the button functionality, the image control <idl>com.sun.star.awt.UnoControlImageControl</idl> is selected. The location of the graphic for the command button is set by the ImageURL property. Usually, the size of the image does not match the size of the control, therefore the image control automatically scales the image to the size of the control by setting the ScaleImage property to True.

    oImageControlModel = oDialog.Model.ImageControl1
    oImageControlModel.ImageURL =
        "file:///D:/Office60/share/gallery/photos/beach.jpg"
    oImageControlModel.ScaleImage = True

    Check Box

    The check box control <idl>com.sun.star.awt.UnoControlCheckBox</idl> is used in groups to display multiple choices so that the user can select one or more choices. When a check box is selected it displays a check mark. Check boxes work independently of each other, thus different from option buttons. A user can select any number of check boxes at the same time.

    The property State, where 0 is not checked, 1 is checked, 2 is don't know, accesses and changes the state of a checkbox. The tri-state mode of a check box is enabled by setting the TriState property to True. A tri-state check box provides the additional state "don't know", that is used to give the user the option of setting or unsetting an option.

    oCheckBoxModel = oDialog.Model.CheckBox3
    oCheckBoxModel.TriState = True
    oCheckBoxModel.State = 2

    The same result is achieved by using the <idl>com.sun.star.awt.XCheckBox</idl> interface:

    oCheckBox = oDialog.getControl("CheckBox3")
    oCheckBox.enableTriState( True )
    oCheckBox.setState( 2 )

    Option Button

    An option button control <idl>com.sun.star.awt.UnoControlRadioButton</idl> is a simple switch with two states, that is selected by the user. Usually option buttons are used in groups to display several options, that the user may select. While option buttons and check boxes seem to be similar, selecting one option button deselects all the other option buttons in the same group.

    Note pin.svg

    Note:
    Note, that option buttons that belong to the same group must have consecutive tab indices. Two groups of option buttons can be separated by any control with a tab index that is between the tab indices of the two groups.

    Usually a group box, or horizontal and vertical lines are used, because those controls visually group the option buttons together, but in principle this can be any control. There is no functional relationship between an option button and a group box. Option buttons are grouped through consecutive tab indices only.

    The state of an option button is accessed by the State property of its Model, where 0 is not checked and 1 is checked.

    Function IsChecked( oOptionButtonModel As Object ) As Boolean
        Dim bChecked As Boolean
        If oOptionButtonModel.State = 1 Then
            bChecked = True
        Else
            bChecked = False
        End If
        IsChecked = bChecked
    End Function

    The state of an option button is also returned by the State property of the control, where False is not checked and True is checked. The code is greatly simplified:

    If oOptionButton.State Then
        ' The option is checked
    Else
        ' The option is not checked
    End If

    Label Field

    A label field control <idl>com.sun.star.awt.UnoControlFixedText</idl> displays text that the user can not edit on the screen. For example, the label field is used to add descriptive labels to text fields, list boxes, and combo boxes. The actual text displayed in the label field is controlled by the Label property. The Align property allows the user to set the alignment of the text in the control to the left (0), center (1) or right (2). By default, the label field displays the text from the Label property in a single line. If the text exceeds the width of the control, the text is truncated. This behavior is changed by setting the MultiLine property to True, so that the text is displayed on more than one line, if necessary. By default, the label field control is drawn without any border. However, the label field appears with a border if the Border property is set, where 0 is no border, 1 is a 3D border, and 2 is a simple border. The font attributes of the text in the label field are specified by the FontDescriptor property. It is recommended to set this property with the property browser in the dialog editor.

    Label fields are used to define shortcut keys for controls without labels. A shortcut key can be defined for any control with a label by adding a tilde (~) before the character that will be used as a shortcut. When the user presses the character key simultaneously with the Alt key, the control automatically gets the focus. To assign a shortcut key to a control without a label, for example, a text field, the label field is used. The tilde prefixes the corresponding character in the Label property of the label field. As the label field cannot receive focus, the focus automatically moves to the next control in the tab order. Therefore, it is important that the label field and the text field have consecutive tab indices.

    oLabelModel = oDialog.Model.Label1
    oLabelModel.Label = "Enter ~Text"

    Text Field

    The text field control <idl>com.sun.star.awt.UnoControlEdit</idl> is used to get input from the user at runtime. In general, the text field is used for editable text, but it can also be made read-only by setting the ReadOnly property to True. The actual text displayed in a text field is controlled by the Text property. The maximum number of characters that can be entered by the user is specified with the MaxTextLen property. A value of 0 means that there is no limitation. By default, a text field displays a single line of text. This behavior is changed by setting the property MultiLine to True. The properties HScroll and VScroll displays a horizontal and vertical scroll bar.

    When a text field receives the focus by pressing the Tab ↹ key the displayed text is selected and highlighted by default. The default cursor position within the text field is to the right of the existing text. If the user starts typing while a block of text is selected, the selected text is replaced. In some cases, the user may change the default selection behavior and set the selection manually. This is done using the <idl>com.sun.star.awt.XTextComponent</idl> interface:

    Dim sText As String
    Dim oSelection As New com.sun.star.awt.Selection
    
    REM get control
    oTextField = oDialog.getControl("TextField1")
    
    REM set displayed text
    sText = "Displayed Text"
    oTextField.setText( sText )
    
    REM set selection
    oSelection.Min = 0
    oSelection.Max = Len( sText )
    oTextField.setSelection( oSelection )

    Or in short:

    Dim oSelection As New com.sun.star.awt.Selection
    
    oTextField = oDialog.getControl("TextField1")
    
    oTextField.Text = "Displayed Text"
    
    oSelection.Min = 0
    oSelection.Max = Len( sText )
    oTextField.Selection = oSelection

    The text field control is also used for entering passwords. The property EchoChar specifies the character that is displayed in the text field while the user enters the password. In this context, the MaxTextLen property is used to limit the number of characters that are typed in:

    oTextFieldModel = oDialog.Model.TextField1
    oTextFieldModel.EchoChar = Asc("*")
    oTextFieldModel.MaxTextLen = 8

    A user can enter any kind of data into a text field, such as numerical values and dates. These values are always stored as a string in the Text property, thus leading to problems when evaluating the user input. Therefore, consider using a date field, time field, numeric field, currency field or formatted field instead.

    List Box

    The list box control <idl>com.sun.star.awt.UnoControlListBox</idl> displays a list of items that the user can select one or more of. If the number of items exceeds what can be displayed in the list box, scroll bars automatically appear on the control. If the Dropdown property is set to True, the list of items is displayed in a drop-down box. In this case, the maximum number of line counts in the drop-down box are specified with the LineCount property. The actual list of items is controlled by the StringItemList property. All selected items are controlled by the SelectedItems property. If the MultiSelection property is set to True, more than one entry can be selected.

    It may be easier to use the <idl>com.sun.star.awt.XListBox</idl> interface when working with list boxes, because an item can be added to a list at a specific position with the addItem method. For example, an item is added at the end of the list by:

    Dim nCount As Integer, oListBox As Object
    
    oListBox = oDialog.getControl("ListBox1")
    nCount = oListBox.getItemCount()
    oListBox.addItem( "New Item", nCount )

    Multiple items are added with the help of the addItems method. The removeItems method is used to remove items from a list. For example, the first entry in a list is removed by:

    Dim nPos As Integer, nCount As Integer
    
    nPos = 0
    nCount = 1
    oListBox.removeItems( nPos, nCount )

    A list box item can be preselected with the selectItemPos, selectItemsPos and selectItem methods. For example, the first entry in a list box can be selected by:

    oListBox.selectItemPos( 0, True )

    The currently selected item is obtained with the getSelectedItem method:

    Dim sSelectedItem As String
    sSelectedItem = oListBox.getSelectedItem()

    The position of the currently selected item is obtained with the getSelectedItemPos method:

    Dim selectPos As Integer
    selectPos = oListBox.getSelectedItemPos()

    Combo Box

    The combo box control <idl>com.sun.star.awt.UnoControlComboBox</idl> presents a list of choices to the user. Additionally, it contains a text field allowing the user to input a selection that is not on the list. A combo box is used when there is only a list of suggested choices, whereas a list box is used when the user input is limited only to the list.

    The features and properties of a combo box and a list box are similar. Also in a combo box the list of items can be displayed in a drop-down box by setting the Dropdown property to True. The actual list of items is accessible through the StringItemList property. The text displayed in the text field of the combo box is controlled by the Text property. For example, if a user selects an item from the list, the selected item is displayed in the text field and is obtained from the Text property:

    Function GetSelectedItem( oComboBoxModel As Object ) As String
        GetSelectedItem = oComboBoxModel.Text
    End Function

    When a user types text into the text field of the combo box, the automatic word completion is a useful feature and is enabled by setting the Autocomplete property to True. It is recommended to use the <idl>com.sun.star.awt.XComboBox</idl> interface when accessing the items of a combo box:

    Dim nCount As Integer
    Dim sItems As Variant
    
    REM get control
    oComboBox = oDialog.getControl("ComboBox1")
    
    REM first remove all old items from the list
    nCount = oComboBox.getItemCount()
    oComboBox.removeItems( 0, nCount )
    
    REM add new items to the list
    sItems = Array( "Item1", "Item2", "Item3", "Item4", "Item5" )
    oComboBox.addItems( sItems, 0 )

    Horizontal/Vertical Scroll Bar

    If the visible area in a dialog is smaller than the displayable content, the scroll bar control <idl>com.sun.star.awt.UnoControlScrollBar</idl> provides navigation through the content by scrolling horizontally or vertically. In addition, the scroll bar control is used to provide scrolling to controls that do not have a built-in scroll bar.

    The orientation of a scroll bar is specified by the Orientation property and can be horizontal or vertical. A scroll bar has a thumb (scroll box) that the user can drag with the mouse to any position along the scroll bar. The position of the thumb is controlled by the ScrollValue property. For a horizontal scroll bar, the left-most position corresponds to the minimum scroll value of 0 and the right-most position to the maximum scroll value defined by the ScrollValueMax property. A scroll bar also has arrows at its end that when clicked or held, incrementally moves the thumb along the scroll bar to increase or decrease the scroll value. The change of the scroll value per mouse click on an arrow is specified by the LineIncrement property. When clicking in a scroll bar in the region between the thumb and the arrows, the scroll value increases or decreases by the value set for the BlockIncrement property. The thumb position represents the portion of the displayable content that is currently visible in a dialog. The visible size of the thumb is set by the VisibleSize property and represents the percentage of the currently visible content and the total displayable content.

    oScrollBarModel = oDialog.Model.ScrollBar1
    oScrollBarModel.ScrollValueMax = 100
    oScrollBarModel.BlockIncrement = 20
    oScrollBarModel.LineIncrement = 5
    oScrollBarModel.VisibleSize = 20

    The scroll bar control uses the adjustment event <idl>com.sun.star.awt.AdjustmentEvent</idl> to monitor the movement of the thumb along the scroll bar. In an event handler for adjustment events the developer may change the position of the visible content on the dialog as a function of the ScrollValue property. In the following example, the size of a label field exceeds the size of the dialog. Each time the user clicks on the scrollbar, the macro AdjustmentHandler() is called and the position of the label field in the dialog is changed according to the scroll value.

    Sub AdjustmentHandler()
        Dim oLabelModel As Object
        Dim oScrollBarModel As Object
        Dim ScrollValue As Long, ScrollValueMax As Long
        Dim VisibleSize As Long
        Dim Factor As Double
        Static bInit As Boolean
        Static PositionX0 As Long
        Static Offset As Long
        REM get the model of the label control
        oLabelModel = oDialog.Model.Label1
        REM on initialization remember the position of the label control and calculate offset
        If bInit = False Then
            bInit = True
            PositionX0 = oLabelModel.PositionX
            OffSet = PositionX0 + oLabelModel.Width - (oDialog.Model.Width - Border)
        End If
        REM get the model of the scroll bar control
        oScrollBarModel = oDialog.Model.ScrollBar1
        REM get the actual scroll value
        ScrollValue = oScrollBarModel.ScrollValue
        REM calculate and set new position of the label control
        ScrollValueMax = oScrollBarModel.ScrollValueMax
        VisibleSize = oScrollBarModel.VisibleSize
        Factor = Offset / (ScrollValueMax - VisibleSize)
        oLabelModel.PositionX = PositionX0 - Factor * ScrollValue
    End Sub

    Group Box

    The group box control <idl>com.sun.star.awt.UnoControlGroupBox</idl> creates a frame to visually group other controls together, such as option buttons and check boxes. Note that the group box control does not provide any container functionality for other controls, it only has visual functionality. For more details, see Option Button.

    The group box contains a label embedded within the border and is set by the Label property. In most cases, the group box control is only used passively.

    Progress Bar

    The progress bar control <idl>com.sun.star.awt.UnoControlProgressBar</idl> displays a growing or shrinking bar to give the user feedback during an operation, for example, the completion of a lengthy task. The minimum and the maximum progress value of the control is set by the ProgressValueMin and the ProgressValueMax properties. The progress value is controlled by the ProgressValue property. By default, the progress bar is blue, but the fill color can be changed by setting the FillColor property. The functionality of a progress bar is demonstrated in the following example:

    Sub ProgressBarDemo()
      Dim oProgressBar as Object, oProgressBarModel As Object, oDialog as Object
      Dim ProgressValue As Long
      REM Dialog1 contains progress bar ProgressBar1 saved in standard library
      DialogLibraries.loadLibrary("Standard")
      oDialog = CreateUnoDialog(DialogLibraries.Standard.Dialog1)
      REM progress bar settings
      Const ProgressValueMin = 0
      Const ProgressValueMax = 40
      Const ProgressStep = 4
      REM set minimum and maximum progress value
      oProgressBarModel = oDialog.getModel().getByName( "ProgressBar1" )
      oProgressBarModel.setPropertyValue( "ProgressValueMin", ProgressValueMin)
      oProgressBarModel.setPropertyValue( "ProgressValueMax", ProgressValueMax)
      REM show progress bar
      oDialog.setVisible( True )
      REM increase progress value every second
      For ProgressValue = ProgressValueMin To ProgressValueMax Step ProgressStep
        oProgressBarModel.setPropertyValue( "ProgressValue", ProgressValue )
        Wait 1000
      Next ProgressValue
    End Sub

    Horizontal/Vertical Line

    The line control <idl>com.sun.star.awt.UnoControlFixedLine</idl> creates simple lines in a dialog. In most cases, the line control is used to visually subdivide a dialog. The line control can have horizontal or vertical orientation that is specified by the Orientation property. The label of a line control is set by the Label property. Note that the label is only displayed if the control has a horizontal orientation.

    Date Field

    The date field control <idl>com.sun.star.awt.UnoControlDateField</idl> extends the text field control and is used for displaying and entering dates. The date displayed in the date field is controlled by the Date property. The date value is of type Long and must be specified in the format YYYYMMDD, for example, the date September 30th, 2020 is set in the following format:

    oDateFieldModel = oDialog.Model.DateField1
    oDateFieldModel.Date = 20200930

    The current date is set by using the Date and CDateToIso runtime functions:

    oDateFieldModel.Date = CDateToIso( Date() )

    The minimum and the maximum date that the user can enter is defined by the DateMin and the DateMax property. The format of the displayed date is specified by the DateFormat and the DateShowCentury property, but the usage of DateShowCentury is deprecated. Some formats are dependent on the system settings. If the StrictFormat property is set to True, the date entered by the user is checked during input. The Dropdown property enables a calendar that the user can drop down to select a date.

    Dropdown is currently not working by program, but you can set it with the Control Properties in the IDE.

    Time Field

    The time field control <idl>com.sun.star.awt.UnoControlDateField</idl> displays and enters time values. The time value are set and retrieved by the Time property. The time value is of type Long and is specified in the format HHMMSShh, where HH are hours, MM are minutes, SS are seconds and hh are hundredth seconds. For example, the time 15:18:23 is set by:

    oTimeFieldModel = oDialog.Model.TimeField1
    oTimeFieldModel.Time = 15182300

    The minimum and maximum time value that can be entered is given by the TimeMin and TimeMax property. The format of the displayed time is specified by the TimeFormat property.

    The time value is checked during input by setting the StrictFormat property to True.

    Short time format is currently not working.

    Numeric Field

    It is recommended to use the numeric field control <idl>com.sun.star.awt.UnoControlNumericField</idl> if the user input is limited to numeric values. The numeric value is controlled by the Value property, which is of type Double. A minimum and maximum value for user input is defined by the ValueMin and the ValueMax property. The decimal accuracy of the numeric value is specified by the DecimalAccuracy property, for example, a value of 6 corresponds to 6 decimal places. If the ShowThousandsSeparator property is set to True, a thousands separator is displayed. The numeric field also has a built-in spin button, enabled by the Spin property. The spin button is used to increment and decrement the displayed numeric value by clicking with the mouse, whereas the step is set by the ValueStep property.

    oNumericFieldModel = oDialog.Model.NumericField1
    oNumericFieldModel.Value = 25.40
    oNumericFieldModel.DecimalAccuracy = 2

    Currency Field

    The currency field control <idl>com.sun.star.awt.UnoControlCurrencyField</idl> is used for entering and displaying currency values. In addition to the currency value, a currency symbol is displayed, that is set by the CurrencySymbol property. If the PrependCurrencySymbol property is set to True, the currency symbol is displayed in front of the currency value.

    oCurrencyFieldModel = oDialog.Model.CurrencyField1
    oCurrencyFieldModel.Value = 500.00
    oCurrencyFieldModel.CurrencySymbol = "€"
    oCurrencyFieldModel.PrependCurrencySymbol = True

    Formatted Field

    The formatted field control <idl>com.sun.star.awt.UnoControlFormattedField</idl> specifies a format that is used for formatting the entered and displayed data. A number formats supplier must be set in the FormatsSupplier property and a format key for the used format must be specified in the FormatKey property. It is recommended to use the property browser in the dialog editor for setting these properties. Supported number formats are number, percent, currency, date, time, scientific, fraction and boolean values. Therefore, the formatted field can be used instead of a date field, time field, numeric field or currency field. The NumberFormatsSupplier is described in Office Development.

    Pattern Field

    The pattern field control <idl>com.sun.star.awt.UnoControlPatternField</idl> displays and enters a string according to a specified pattern. The entries that the user enters in the pattern field are defined in the EditMask property as a special character code. The length of the edit mask determines the number of the possible input positions. If a character is entered that does not correspond to the edit mask, the input is rejected. For example, in the edit mask "NNLNNLLLLL" the character L has the meaning of a text constant and the character N means that only the digits 0 to 9 can be entered. A complete list of valid characters can be found in the LibreOffice online help. The LiteralMask property contains the initial values that are displayed in the pattern field. The length of the literal mask should always correspond to the length of the edit mask. An example of a literal mask which fits to the above mentioned edit mask would be "__.__.2002". In this case, the user enters only 4 digits when entering a date.

    oPatternFieldModel = oDialog.Model.PatternField1
    oPatternFieldModel.EditMask = "NNLNNLLLLL"
    oPatternFieldModel.LiteralMask = "__.__.2002"

    More information at: Documentation/OOo3_User_Guides/Writer_Guide/Form_controls_reference_Pattern_field

    File Control

    The file control <idl>com.sun.star.awt.UnoControlFileControl</idl> has all the properties of a text field control, with the additional feature of a built-in command button. When the button is clicked, the file dialog shows up. The directory that the file dialog initially displays is set by the Text property.

    The directory must be given as a system path, file URLs do not work at the moment. In Basic you can use the runtime function ConvertToURL() to convert system paths to URLs.

    oFileControl = oDialog.Model.FileControl1
    oFileControl.Text = "D:\Programme\Office60"

    Filters for the file dialog can not be set or appended for the file control. An alternative way is to use a text field and a command button instead of a file control and assign a macro to the button which instantiates the file dialog <idl>com.sun.star.ui.dialogs.FilePicker</idl> at runtime. An example is provided below.

    Once the dialog is open, the user may write a directory address in the text field. Then he/she clicks the button. The file dialog will display the file names in that directory, or by default in the work directory. The selected file name is stored in the text field.

    Sub OpenFileDialog()
        Dim oFilePicker As Object, oSimpleFileAccess As Object
        Dim oSettings As Object, oPathSettings As Object
        Dim oTextField As Object, oTextFieldModel As Object
        Dim sFileURL As String
        Dim sFiles As Variant
        REM file dialog
        oFilePicker = CreateUnoService( "com.sun.star.ui.dialogs.FilePicker" )
        REM set filter
        oFilePicker.AppendFilter( "All files (*.*)", "*.*" )
        oFilePicker.AppendFilter( "StarOffice 6.0 Text Text Document", "*.sxw" )
        oFilePicker.AppendFilter( "StarOffice 6.0 Spreadsheet", "*.sxc" )
        oFilePicker.SetCurrentFilter( "All files (*.*)" )
        REM if no file URL is set, get path settings from configuration
        oTextFieldModel = oDialog.Model.TextField1
        sFileURL = ConvertToURL( oTextFieldModel.Text )
        If sFileURL = "" Then
            oPathSettings = CreateUnoService( "com.sun.star.util.PathSettings" )
            sFileURL = oPathSettings.Work
        End If
        REM set display directory
        oSimpleFileAccess = CreateUnoService( "com.sun.star.ucb.SimpleFileAccess" )
        If oSimpleFileAccess.exists( sFileURL ) And oSimpleFileAccess.isFolder( sFileURL ) Then
            oFilePicker.setDisplayDirectory( sFileURL )
        End If
        REM execute file dialog
        If oFilePicker.execute() Then
            sFiles = oFilePicker.getFiles()
            sFileURL = sFiles(0)
            If oSimpleFileAccess.exists( sFileURL ) Then
                REM set file path in text field
                oTextField = oDialog.GetControl("TextField1")
                oTextField.SetText( ConvertFromURL( sFileURL ) )
            End If
        End If
    End Sub

    Creating Dialogs at Runtime

    When using LibreOffice Basic, the dialog editor is a tool for designing dialogs. Refer to LibreOffice Basic IDE for additional information. Since OpenOffice.org 2.0.0, dialogs that have been built with the dialog editor can be loaded by a macro written in any of the supported scripting framework languages (BeanShell, JavaScript, Java, LibreOffice Basic) by using the <idl>com.sun.star.awt.XDialogProvider</idl> API. See section Using the Scripting Framework for more details.

    In addition, it is also possible to create dialogs at runtime in a similar way as Java Swing components are created. Also, the event listeners are registered at runtime at the appropriate controls.

    An example dialog

    In the Java example described in this section, a simple modal dialog is created at runtime containing a command button and label field. Each time the user clicks on the button, the label field is updated and the total number of button clicks is displayed.

    The dialog is implemented as a UNO component in Java that is instantiated with the service name com.sun.star.examples.SampleDialog. For details about writing a Java component and the implementation of the UNO core interfaces, refer to Storing the Service Manager for Further Use. The method that creates and executes the dialog is shown below.

    /** method for creating a dialog at runtime
    */
    private void createDialog() throws com.sun.star.uno.Exception {
        // get the service manager from the component context
        XMultiComponentFactory xMultiComponentFactory = _xComponentContext.getServiceManager();
        // create the dialog model and set the properties
        Object dialogModel = xMultiComponentFactory.createInstanceWithContext(
            "com.sun.star.awt.UnoControlDialogModel", _xComponentContext);
        XPropertySet xPSetDialog = (XPropertySet)UnoRuntime.queryInterface(
            XPropertySet.class, dialogModel);
        xPSetDialog.setPropertyValue("PositionX", new Integer(100));
        xPSetDialog.setPropertyValue("PositionY", new Integer(100));
        xPSetDialog.setPropertyValue("Width", new Integer(150));
        xPSetDialog.setPropertyValue("Height", new Integer(100));
        xPSetDialog.setPropertyValue("Title", new String("Runtime Dialog Demo"));
        // get the service manager from the dialog model
        XMultiServiceFactory xMultiServiceFactory = (XMultiServiceFactory)UnoRuntime.queryInterface(
            XMultiServiceFactory.class, dialogModel);
        // create the button model and set the properties
        Object buttonModel = xMultiServiceFactory.createInstance(
            "com.sun.star.awt.UnoControlButtonModel" );
        XPropertySet xPSetButton = (XPropertySet)UnoRuntime.queryInterface(
            XPropertySet.class, buttonModel);
        xPSetButton.setPropertyValue("PositionX", new Integer(50));
        xPSetButton.setPropertyValue("PositionY", new Integer(30));
        xPSetButton.setPropertyValue("Width", new Integer(50));
        xPSetButton.setPropertyValue("Height", new Integer(14));
        xPSetButton.setPropertyValue("Name", _buttonName);
        xPSetButton.setPropertyValue("TabIndex", new Short((short)0));
        xPSetButton.setPropertyValue("Label", new String("Click Me"));
        // create the label model and set the properties
        Object labelModel = xMultiServiceFactory.createInstance(
            "com.sun.star.awt.UnoControlFixedTextModel" );
        XPropertySet xPSetLabel = ( XPropertySet )UnoRuntime.queryInterface(
            XPropertySet.class, labelModel );
        xPSetLabel.setPropertyValue("PositionX", new Integer(40));
        xPSetLabel.setPropertyValue("PositionY", new Integer(60));
        xPSetLabel.setPropertyValue("Width", new Integer(100));
        xPSetLabel.setPropertyValue("Height", new Integer(14));
        xPSetLabel.setPropertyValue("Name", _labelName);
        xPSetLabel.setPropertyValue("TabIndex", new Short((short)1));
        xPSetLabel.setPropertyValue("Label", _labelPrefix);
        // insert the control models into the dialog model
        XNameContainer xNameCont = (XNameContainer)UnoRuntime.queryInterface(
            XNameContainer.class, dialogModel);
        xNameCont.insertByName(_buttonName, buttonModel);
        xNameCont.insertByName(_labelName, labelModel);
        // create the dialog control and set the model
        Object dialog = xMultiComponentFactory.createInstanceWithContext(
            "com.sun.star.awt.UnoControlDialog", _xComponentContext);
        XControl xControl = (XControl)UnoRuntime.queryInterface(
            XControl.class, dialog );
        XControlModel xControlModel = (XControlModel)UnoRuntime.queryInterface(
            XControlModel.class, dialogModel);
        xControl.setModel(xControlModel);
        // add an action listener to the button control
        XControlContainer xControlCont = (XControlContainer)UnoRuntime.queryInterface(
            XControlContainer.class, dialog);
        Object objectButton = xControlCont.getControl("Button1");
        XButton xButton = (XButton)UnoRuntime.queryInterface(XButton.class, objectButton);
        xButton.addActionListener(new ActionListenerImpl(xControlCont));
        // create a peer
        Object toolkit = xMultiComponentFactory.createInstanceWithContext(
            "com.sun.star.awt.Toolkit", _xComponentContext);
        XToolkit xToolkit = (XToolkit)UnoRuntime.queryInterface(XToolkit.class, toolkit);
        XWindow xWindow = (XWindow)UnoRuntime.queryInterface(XWindow.class, xControl);
        xWindow.setVisible(false);
        xControl.createPeer(xToolkit, null);
        // execute the dialog
        XDialog xDialog = (XDialog)UnoRuntime.queryInterface(XDialog.class, dialog);
        xDialog.execute();
        // dispose the dialog
        XComponent xComponent = (XComponent)UnoRuntime.queryInterface(XComponent.class, dialog);
        xComponent.dispose();
    }

    First, a dialog model is created by prompting the ServiceManager for the <idl>com.sun.star.awt.UnoControlDialogModel</idl> service. Then, the position, size and title of the dialog are set using the <idl>com.sun.star.beans.XPropertySet</idl> interface. In performance critical applications, the use of the <idl>com.sun.star.beans.XMultiPropertySet</idl> interface is recommended. At this point, the dialog model describes an empty dialog, which does not contain any control models.

    All control models in a dialog container have the common properties "PositionX", "PositionY", "Width", "Height", "Name", "TabIndex", "Step" and "Tag". These properties are optional and only added if the control model is created by a special object factory, namely the dialog model. Therefore, a dialog model also supports the <idl>com.sun.star.lang.XMultiServiceFactory</idl> interface. If the control model is created by the ServiceManager, these common properties are missing.

    Note pin.svg

    Note:
    Note that control models have the common properties "PositionX", "PositionY", "Width", "Height", "Name", "TabIndex", "Step" and "Tag" only if they were created by the dialog model that they belong to.

    After the control models for the command button and label field are created, their position, size, name, tab index and label are set. Then, the control models are inserted into the dialog model using the <idl>com.sun.star.container.XNameContainer</idl> interface. The model of the dialog has been fully described.

    To display the dialog on the screen, a dialog control <idl>com.sun.star.awt.UnoControlDialog</idl> is created and the corresponding model is set. An action listener is added to the button control, because the label field is updated whenever the user clicks on the command button. The listener is explained below. Before the dialog is shown, a window or a peer is created on the screen. Finally, the dialog is displayed on the screen using the execute method of the <idl>com.sun.star.awt.XDialog</idl> interface.

    The implementation of the action listener is shown in the following example.

    /** action listener
    */
    public class ActionListenerImpl implements com.sun.star.awt.XActionListener {
        private int _nCounts = 0;
        private XControlContainer _xControlCont;
    
        public ActionListenerImpl(XControlContainer xControlCont) {
            _xControlCont = xControlCont;
        }
    
        // XEventListener
        public void disposing(EventObject eventObject) {
            _xControlCont = null;
        }
    
        // XActionListener
        public void actionPerformed(ActionEvent actionEvent) {
            // increase click counter
            _nCounts++;
    
            // set label text
            Object label = _xControlCont.getControl("Label1");
            XFixedText xLabel = (XFixedText)UnoRuntime.queryInterface(XFixedText.class, label);
            xLabel.setText(_labelPrefix + _nCounts);
        }
    }

    The action listener is fired each time the user clicks on the command button. In the actionPerformed method of the <idl>com.sun.star.awt.XActionListener</idl> interface, an internal counter for the number of button clicks is increased. Then, this number is updated in the label field. In addition, the disposing method of the parent interface <idl>com.sun.star.lang.XEventListener</idl> is implemented.

    Our sample component executes the dialog from within the office by implementing the trigger method of the <idl>com.sun.star.task.XJobExecutor</idl> interface:

    public void trigger(String sEvent) {
        if (sEvent.equals("execute")) {
            try {
                createDialog();
            }
            catch (Exception e) {
                throw new com.sun.star.lang.WrappedTargetRuntimeException(e.getMessage(), this, e);
            }
        }
    }

    A simple LibreOffice Basic macro that instantiates the service of our sample component and executes the dialog is shown below.

    Sub Main
        Dim oJobExecutor
        oJobExecutor = CreateUnoService("com.sun.star.examples.SampleDialog")
        oJobExecutor.trigger("execute")
    End Sub

    In future versions of LibreOffice, a method for executing dialogs created at runtime will be provided.

    Library File Structure

    This section describes how libraries are stored. Generally all data is stored in XML format. Four different XML document types that arespecified in the DTD files installed in <OfficePath>/share/dtd/officedocument are used:

    • A library container is described by a library container index file following the specification given in libraries.dtd. In this file, each library in the library container is described by its name, a flag if the library is a link, the StorageURL (describing where the library is stored) and, only in case of a link, the link read-only status.
    • A library is described by a library index file following the specification given in library.dtd. This file contains the library name, a flag for the read-only status, a flag if the library is password protected (see below) and the name of each library element.
    • A Basic source code module is described in a file following the specification given in module.dtd. This file contains the module name, the language (at the moment only LibreOffice Basic is supported) and the source code.
    • A dialog is described in a file following the specification given in dialog.dtd. The file contains all data to describe a dialog. As this format is extensive, it is not possible to describe it in this document.

    Additionally, a binary format is used to store compiled Basic code for password protected Basic libraries. This is described in more detail in Library File Structure.

    Warning.svg

    Warning:
    In a password protected Basic library, the password is used to scramble the source code using the Blowfish algorithm. The password itself is not stored, so when the password for a Basic library is lost, the corresponding Basic source code is lost also. There is no retrieval method if this happens.


    Besides the XML format of the library description files, it is necessary to understand the structure in which these files are stored. This is different for application and document libraries. Application libraries are stored directly in the system file system and document libraries are stored inside the document's package file. The following sections describe the structure and combination of library container and library structures.

    Application Library Container

    In an LibreOffice installation the application library containers for Basic and dialogs are located in the directory <OfficePath>/share/basic or <OfficeUserPath>/user/basic. The library container index files are named script.xlc for the Basic and dialog.xlc for the Dialog library container. The "lc" in .xlc stands for library container.

    The same directory contains the libraries created by the user. Initially only the library Standard exists for Basic and dialogs using the same directory. The structure of the library inside the directory is explained in the next section.

    The user/basic directory is not the only place in the LibreOffice installation where libraries are stored. Most of the autopilots integrated in LibreOffice are realized in Basic, and the corresponding Basic and dialog libraries are installed in the directory <OfficePath>/share/basic. These libraries are listed in the library container index file as read-only links.

    It is necessary to distinguish between libraries created by the user and the autopilot libraries. The autopilot libraries are installed in a directory that is shared between different users. In a network installation, the share directory is located somewhere on a server, so that the autopilot libraries cannot be owned directly by the user-specific library containers.

    In the file system, a library is represented by a directory. The directory's name is the same as the library name. The directory contains all files that are necessary for the library.

    Basic libraries can be protected with a password, so that the source code cannot be read by unauthorized persons. Dialog libraries cannot be protected with a password. This can be handled using the LibreOffice Basic Macro Organizer dialog that is explained in Managing Basic and Dialog Libraries. The password protection of a Basic library also affects the file format.

    Libraries without Password Protection

    Every library element is represented by an XML file named like the element in the directory representing the library. For Basic modules these files, following the specification in module.dtd, have the extension .xba. For dialogs these files, following the specification in dialog.dtd, have the extension .xdl. Additionally, the directory contains a library index file (library.dtd). These index files are named script.xlb for Basic and dialog.xlb for dialog libraries.

    In the following example, an Application Basic library Standard containing two modules Module1 and Module2 is represented by the following directory:

     <DIR> Standard
     |
     |--script.xlb
     |--Module1.xba
     |--Module2.xba
    

    An application dialog library Standard containing two dialogs SmallDialog and BigDialog is represented by the following directory:

     <DIR> Standard
     |
     |--dialog.xlb
     |--SmallDialog.xba
     |--BigDialog.xba
    

    It is also possible that the same directory represents a Basic and a Dialog library. This is the standard case in the LibreOffice, See the chapter Library organization in LibreOffice. When the two example libraries above are stored in the same directory, the files from both libraries are together in the same directory:

     <DIR> Standard
     |
     |--dialog.xlb
     |--script.xlb
     |--Module1.xba
     |--Module2.xba
     |--SmallDialog.xba
     |--BigDialog.xba
    

    The two libraries do not affect each other, because all file names are different. This is also the case if a Basic module and a dialog are named equally, due the different file extensions.

    Libraries with Password Protection

    Only Basic libraries can be password protected. The password protection of a Basic library affects the file format, because binary data has to be stored. In plain XML format, the source code would be readable in the file even if it was not displayed in the Basic IDE. Also, the compiled Basic code has to be stored for each module together with the encrypted sources. This is necessary because, Basic could not access the source code and compile it as long as the password is unknown in contrast to libraries without password protection. Without storing the compiled code, Basic could only execute password-protected libraries once the user supplied the correct password. The whole purpose of the password feature is to distribute programs without giving away the password and source code, therefore this would not be feasible.

    The following example shows a password-protected application Basic library Library1, containing three modules Module1, Module1 and Module3, is represented by the following directory:

     <DIR> Library1
     |
     |--script.xlb
     |--Module1.pba
     |--Module2.pba
     |--Module3.pba
    

    The file script.xlb does not differ from the case without a password, except for the fact that the password protected status of the library is reflected by the corresponding flag.

    Each module is represented by a .pba file. Like LibreOffice documents, these files are package files ("pba" stands for package basic) and contain a sub structure that can be viewed with any zip tool. ).

    A module package file has the following content:

     <PACKAGE> Module1.pba
     |
     |--<DIR> Meta-Inf          ' Content is not displayed here
     |--code.bin
     |--source.xml
    

    The Meta-Inf directory is part of every package file and will not be explained in this document. The file code.bin contains the compiled Basic code and the file source.xml contains the Basic source code encrypted with the password.

    Document Library Container

    While application libraries are stored directly in the file system, document libraries are stored inside the document's package file. In documents, the Basic library container and dialog library container are stored separately:

    • The root of the Basic library container hierarchy is a folder inside the package file named Basic. This folder is not created when the Basic library container contains an empty Standard library in the case of a new document.
    • The root of the dialog library container hierarchy is a folder inside the package file named Dialogs. This folder is not created when the dialog library container contains an empty Standard library in the case of a new document.

    The libraries are stored as sub folders in these library container folders. The structure inside the libraries is basically the same as in an application. One difference relates to the stream - "files" inside the package or package folders – names. In documents, all XML stream or file names have the extension .xml. Special extensions like .xba, .xdl are not used. Instead of different extensions, the names are extended for the library and library container index files. In documents they are named script-lc.xml (Basic library container index file), script-lb.xml (Basic library index file), dialog-lc.xml (dialog library container index file) and dialog-lb.xml (dialog library index file).

    In example 1, the package structure for a document with one Basic Standard library containing three modules:

     <Package> ExampleDocument1
     |
     |--<DIR> Basic
     |  |
     |  |--<DIR> Standard      ' Folder: Contains library "Standard"
     |  |  |
     |  |  |--Module1.xml      ' Stream: Basic module file
     |  |  |--Module2.xml      ' Stream: Basic module file
     |  |  |--Module3.xml      ' Stream: Basic module file
     |  |  |--script-lb.xml    ' Stream: Basic library index file
     |  |
     |  |--script-lc.xml       ' Stream: Basic library container index file
     |
     | ' From here the folders and streams have nothing to do with libraries
     |--<DIR> Meta-Inf
     |--content.xml
     |--settings.xml
     |--styles.xml
    

    In example 2, package structure for a document with two Basic and one dialog libraries:

     <Package> ExampleDocument2
     |
     |--<DIR> Basic
     |  |
     |  |--<DIR> Standard      ' Folder: Contains library "Standard"
     |  |  |
     |  |  |--Module1.xml      ' Stream: Basic module file
     |  |  |--Module2.xml      ' Stream: Basic module file
     |  |  |--script-lb.xml    ' Stream: Basic library index file
     |  |
     |  |--<DIR> Library1      ' Folder: Contains library "Library1"
     |  |  |
     |  |  |--Module1.xml      ' Stream: Basic module file
     |  |  |--script-lb.xml    ' Stream: Basic library index file
     |  |
     |  |--script-lc.xml       ' Stream: Basic library container index file
     |
     |--<DIR> Dialogs
     |  |
     |  |--<DIR> Standard      ' Folder: Contains library "Standard"
     |  |  |
     |  |  |--Dialog1.xml      ' Stream: Dialog file
     |  |  |--dialog-lb.xml    ' Stream: Dialog library index file
     |  |
     |  |--<DIR> Library1      ' Folder: Contains library "Library1"
     |  |  |
     |  |  |--Dialog1.xml      ' Stream: Dialog file
     |  |  |--Dialog2.xml      ' Stream: Dialog file
     |  |  |--dialog-lb.xml    ' Stream: Dialog library index file
     |  |
     |  |--dialog-lc.xml       ' Stream: Dialog library container index file
     |
     | ' From here the folders and streams have nothing to do with libraries
     |--<DIR> Meta-Inf
     |--content.xml
     |--settings.xml
     |--styles.xml
    

    If a document Basic library is password protected, the file structure does not differ as much from an unprotected library as in the Application Basic case. The differences are:

    • The module files of a password-protected Basic library have the same name as without the password protection, but they are scrambled with the password.
    • There is an additional binary file named like the library with the extension .bin for each module. Similar to the file code.bin in the Application Basic .pba files, this file contains the compiled Basic code that executes the module without access to the source code.

    The following example shows the package structure for a document with two Basic and one dialog libraries where only the Basic library Library1 contains any of the modules:

     <Package> ExampleDocument3
     |
     |--<DIR> Basic
     |  |
     |  |--<DIR> Standard      ' Folder: Contains library "Standard"
     |  |  |
     |  |  |--script-lb.xml    ' Stream: Basic library index file
     |  |
     |  |--<DIR> Library1      ' Folder: Contains library "Library1"
     |  |  |
     |  |  |--Module1.xml      ' Stream: Scrambled Basic module source file
     |  |  |--Module1.bin      ' Stream: Basic module compiled code file
     |  |  |--Module2.xml      ' Stream: Scrambled Basic module source file
     |  |  |--Module2.bin      ' Stream: Basic module compiled code file
     |  |  |--Module3.xml      ' Stream: Scrambled Basic module source file
     |  |  |--Module3.bin      ' Stream: Basic module compiled code file
     |  |  |--script-lb.xml    ' Stream: Basic library index file
     |  |
     |  |--script-lc.xml       ' Stream: Basic library container index file
     |
     |--<DIR> Dialogs
     |  |
     |  |--<DIR> Standard      ' Folder: Contains library "Standard"
     |  |  |
     |  |  |--dialog-lb.xml    ' Stream: Dialog library index file
     |  |
     |  |--<DIR> Library1      ' Folder: Contains library "Library1"
     |  |  |
     |  |  |--dialog-lb.xml    ' Stream: Dialog library index file
     |  |
     |  |--dialog-lc.xml       ' Stream: Dialog library container index file
     |
     | ' From here the folders and streams have nothing to do with libraries
     |--<DIR> Meta-Inf
     |--content.xml
     |--settings.xml
     |--styles.xml
    

    This example also shows that a Dialogs folder is created in the document package file although the library Standard and the library Library1 do not contain dialogs. This is done because the Dialog library Library1 would be lost after reloading the document. Only a single empty library Standard is assumed to exist, even if it is not stored explicitly.

    Library Deployment

    LibreOffice has a simple concept to add Basic libraries to an existing installation. Bringing Basic libraries into a LibreOffice installation involves the following steps:

    • Package your libraries as office extension *.oxt package.
    • Start the Extension Manager (Tools - Extension Manager), press the Add button, select the extension package you would like to install and press Ok.

    Alternatively, you can install the extension also via the command line:

     [<OfficePath>/program] $ unopkg add my_package.oxt
    

    The tool analyzes the packages manifest file and install all referenced items accordingly to their mime types.

    The opposite step is necessary to remove a package from your LibreOffice installation:

    • Start the Extension Manager (Tools - Extension Manager), select the package you want to remove and press Remove
    • or via the command line:
     [<OfficePath>/program] $ unopkg remove my_package.oxt
    

    You can run unopkg with the option '--help' or '-h' to get a comprehensive overview of all the switches.

    Package Structure

    An extension package (*.oxt) is a zip file containing Basic libraries, UNO components, type libraries and/or other files. The unopkg tool unzips the content found in the package directory into the cache directory, preserving the file structure of the zip file. Based on the package manifest.xml file the tool installs the referenced content items accordingly to the mime types. All other not referenced content is ignored and is simply unzipped in the cache directory for private usage from package (e.g. images, ...).

    Basic libraries

    The unopkg tool links Basic library files (.xlb) into LibreOffice by adding them to the Basic library container files (.xlc) that reside in the following paths:
    Library File User Installation Shared Installation
    script.xlb <OfficeUserPath>/user/basic/script.xlc <OfficePath>/share/basic/script.xlc
    dialog.xlb <OfficeUserPath>/user/basic/dialog.xlc <OfficePath>/share/basic/dialog.xlc
    The files share/basic/*.xlc are created when new libraries are shared among all users using the unopkg option --shared in a network installation.
    The name of a Basic library is determined by the name of its parent directory. Therefore, package complete library folders, including the parent folders into the UNO Basic package. For example, if your library is named MyLib, there has to be a corresponding folder /MyLib in your development environment. This folder must be packaged completely into the UNO package, so that the *.oxt file contains a structure similar to the following:
     my_package.oxt:
         META-INF/mainfest.xml
         description.xml
         MyLib/
             script.xlb
             dialog.xlb
             Module1.xba
             Dialog1.xba
    

    The appropriate manifest.xml file would look like the following:

    <?xml version="1.0" encoding="UTF-8"?>
    <manifest:manifest xmlns:manifest="http://openoffice.org/2001/manifest">
        <manifest:file-entry manifest:media-type="application/vnd.sun.star.basic-library"
            manifest:full-path="MyLib/"/>
        <manifest:file-entry manifest:media-type="application/vnd.sun.star.dialog-library"
            manifest:full-path="MyLib/"/>
    </manifest:manifest>

    Other package components

    More detailed information about unopkg or Extensions and Extensions deployment in general can be found in the Extensions chapter. Recommended are at least the File Format and the description.xml section.
    Note pin.svg

    Note:
    The autopilot .xlb libraries are registered in the user/basic/*.xlc files, but located in share/basic. This makes it is possible to delete and disable the autopilots for certain users even in a network installation. This is impossible for libraries deployed with the unopkg tool and libraries deployed with the share option are always shared among all users.

    Path Settings

    The package directories are called uno-packages by default. There can be one in <OfficePath>/share for shared installations and another one in <OfficePath>/user for single users. The cache directories are created automatically within the respective uno-packages directory. LibreOffice has to be configured to look for these paths in the uno.ini file (on Windows, unorc on Unix) in <OfficePath>/program. When unopkg is launched, it checks this file for package entries. If they do not exist, the following default values are added to uno(.ini|rc).

     [Bootstrap]
     UNO_SHARED_PACKAGES=${$SYSBINDIR/bootstrap.ini::BaseInstallation}/share/uno_packages
     UNO_SHARED_PACKAGES_CACHE=$UNO_SHARED_PACKAGES/cache
     UNO_USER_PACKAGES=${$SYSBINDIR/bootstrap.ini::UserInstallation}/user/uno_packages
     UNO_USER_PACKAGES_CACHE=$UNO_USER_PACKAGES/cache
    

    The settings reflect the default values for the shared package and cache directory, and the user package and cache directory as described above.

    In a network installation, all users start the office from a common directory on a file server. The administrator installs the extensions package with the --shared option to make it available for all users of this network installation. Note: for shared installation administrator rights are necessary and most often extensions get installed per user.

    Additional Options

    By default, the tool logs all actions into the <cache-dir>/log.txt file. You can switch to another log file through the --log-file <file name> option. Option -v (–verbose) logs to stdout, in addition to the log file.

    The tool handles errors loosely. It continues after errors even if a package cannot be inflated or a shared library cannot be registered. The tool logs these errors and proceeds silently. If you want the tool to stop on every error, switch on the –strict_error handling.

    If there is some inconsistency with the cache and you want to renew it from the ground up, repeating the installation using the expert command unopkg reinstall to force a reinstallation of all deployed extensions.

    Heckert GNU white.svg

    Content on this page is licensed under the Public Documentation License (PDL).