OO-Snippets: Export an ooRexx macro library

Commons

KeywordsooRexx, library, export, addon
LanguageooRexx
ApplicationOffice
AuthorsJosef Frysak (initial)
Supported Versions2.4.1  
Supported OSAll  
QuestionHow to create an addon out of an ooRexx library?
Answer

The macro below, first requests the location of the library and the

destination folder. Next a new addon file is being created by help of the

"Package" service. The "Package" service also provides an

"XSingleServiceFactory" interface to create file and folder objects. To

navigate trough the addon files structure a "XHierarchicalNameAccess"

interface is used. Once the right path object has been retrieved use its

"XNameContainer" interface to add the file objects to the addon file.

To copy the content of a file to the file object use its "XActiveDataSink"

interface and provide the file by opening the file with the

"SimpleFileAccess" service. To make the folder a library, change the

folders "MediaType" property to the apropriate string.

For further details see http://wi.wu-wien.ac.at/rgf/diplomarbeiten/BakkStuff/2008/200809_Frysak/200809_Frysak_Automating_OOo_ooRexx_Nutshells.pdf.

Code-Snippet-Listing (snippet-source)

-- try to get a script context, will be .nil, if script was not invoked by OOo
x_ScriptContext = uno.getScriptContext()
if (x_ScriptContext <> .nil) then
do
   -- invoked by OOo as a macro

   -- get context
   x_ComponentContext = x_ScriptContext~getComponentContext
   -- get desktop (an XDesktop)
   x_Desktop  = x_ScriptContext~getDesktop
   -- get current document
   x_Document = x_ScriptContext~getDocument
end
else  
do
   -- called from outside of OOo, create a connection

   -- connect to Open Office and get component context
   x_ComponentContext = UNO.connect()
   -- create a desktop service and its interface
   service = "com.sun.star.frame.Desktop"
   s_Desktop = x_ComponentContext~getServiceManager~XMultiServiceFactory~createInstance(service)
   x_Desktop = s_Desktop~XDesktop
   -- get the last active document
   x_Document = x_Desktop~getCurrentComponent()  
end




-- first we will ask for the foldername name of the library using the folder dialog
x_MultiServiceFactory = x_ComponentContext~getServiceManager()~XMultiServiceFactory
folderpicker = "com.sun.star.ui.dialogs.OfficeFolderPicker"
s_FolderDialog = x_MultiServiceFactory~createInstance(folderpicker)
x_FolderDialog = s_FolderDialog~XFolderPicker

-- better name for our dialog:
x_FolderDialog~setDescription("Select User Library to Export")

-- get Path to user Macros
s_pathsubst = x_MultiServiceFactory~createInstance("com.sun.star.util.PathSubstitution")
x_stringsubst = s_pathsubst~XStringSubstitution
usermacropath = x_stringsubst~getSubstituteVariableValue("$(user)") || "/Scripts/oorexx"

-- set Directory of Dialog to user macro directory
x_FolderDialog~setDisplayDirectory(usermacropath)

-- start the folder dialog
pathchoosen = x_FolderDialog~execute()
if ( pathchoosen ) then
do
   -- if ok button pressed:
   -- read selected path
   librarypath = x_FolderDialog~getDirectory()

   -- create file access interface to access files
   s_SimpleFileAccess = x_MultiServiceFactory~createInstance("com.sun.star.ucb.SimpleFileAccess")
   x_SimpleFileAccess = s_SimpleFileAccess~XSimpleFileAccess

   -- check if parcel-descriptorfile can be found in library directory
   islibrary = x_SimpleFileAccess~exists(librarypath || "/parcel-descriptor.xml")

   if (islibrary) then
   do
      -- if parcel deskriptor- file can be found:
      -- use Folder Picker again to get destination folder 
      x_FolderDialog~setDescription("Select Export destination")

      if ( x_FolderDialog~execute() ) then
      do
         -- if OK-button pressed:
         -- generate package filename with pathname
         libraryname = getLastFromURL(librarypath)

         savefile = x_FolderDialog~getDirectory() || "/" || libraryname || ".oxt"

         -- if the file already exists, delete it
         delete = SysFileDelete(uno.convertFromURL(savefile))
         if (delete > 2) then
         do
            -- check for file deletion errors (32 = file is blocked by other thread)
            errortext = "File delete error: " || delete || ", accessed by other thread?"
            .bsf.dialog~messageBox(errortext, "ERROR", "error")
            exit 0
         end

         -- now create package object
         s_Package = x_MultiServiceFactory~createInstance("com.sun.star.packages.Package")
         x_PackageInit = s_Package~XInitialization

         -- initialize the package
         c_String = .bsf4rexx~Class.class~forName("java.lang.String")
         initargs = .bsf~bsf.createArray(c_String, 1)
         initargs[1] = savefile
         x_PackageInit~initialize(initargs)

         -- get access to the directory structure of the zip file
         x_HierarchicalNameAccess = s_Package~XHierarchicalNameAccess

         -- get the root item and its containerinterface
         o_RootPackageStream = x_HierarchicalNameAccess~getByHierarchicalName("")
         x_RootNameContainer = o_RootPackageStream~XNameContainer

         -- now create a factory which is able to create new subdirectories and files
         x_PackageFactory = s_Package~XSingleServiceFactory

         -- arguments to create a directory
         -- arguments MUST BE OBJECTS not primitive types!
         .bsf~bsf.import("java.lang.Boolean", "c_Boolean")
         dirargs = .bsf~bsf.createArray(.c_Boolean, 1)
         dirargs[1] = .c_Boolean~new("true")

         s_PackageFolder = x_PackageFactory~createInstanceWithArguments(dirargs)

         -- insert directory object into package
         x_RootNameContainer~insertByName(libraryname, s_PackageFolder)

         -- go into the new created directory and query a container interface for it
         o_LibraryPackageStream = x_HierarchicalNameAccess~getByHierarchicalName(libraryname)
         x_LibraryNameContainer = o_LibraryPackageStream~XNameContainer
         
         -- make this directory an ooRexx script library
         x_LibraryPropertySet = o_LibraryPackageStream~XPropertySet
         scripttype = "application/vnd.sun.star.framework-script;type=ooRexx"
         x_LibraryPropertySet~setPropertyValue("MediaType", scripttype)

         -- set arguments to create a file
         fileargs = .bsf~bsf.createArray(.c_Boolean, 1)
         fileargs[1] = .c_Boolean~new("false")

         -- get all files within librarypath
         libraryfiles = x_SimpleFileAccess~getFolderContents(librarypath, 0)

         -- go trough all files and add them to the package directory
         libraryfileslength = libraryfiles~items
         do counter = 1 to libraryfileslength

            -- first create a fileobject and get the datasink interface of it
            o_FilePackageStream = x_PackageFactory~createInstanceWithArguments(fileargs)
            x_ActiveDataSink  = o_FilePackageStream~XActiveDataSink

            -- next open a file and get its inputstream
            x_InputStream = x_SimpleFileAccess~openFileRead(libraryfiles[counter])

            -- tell the datasink where to read the data from
            -- this starts the reading process
            x_ActiveDataSink~SetInputStream(x_InputStream)

            -- now insert the filled file object to the package
            filename = getLastFromURL(libraryfiles[counter])
            x_LibraryNameContainer~insertByName(filename, o_FilePackageStream)

         end

         /*
         Here we write a file directly into the zip file.
         To do so we first create a new subdirectory and enter it.
         Next a pipeobject is created, this allows sending data from
         an outputinterface to an inputinterface. Now we create a
         Textoutputstream and write data in it. Finally we use a
         Datasink object like the one before to read the data and
         store it in the created file.
         */

         s_InfoPackageFolder = x_PackageFactory~createInstanceWithArguments(dirargs)

         x_RootNameContainer~insertByName("PACKAGEINFO", s_InfoPackageFolder)

         s_InfoPipe = x_MultiServiceFactory~createInstance("com.sun.star.io.Pipe")
         x_InfoPipeOutputStream = s_InfoPipe~XOutputStream
         x_InfoPipeInputStream = s_InfoPipe~XInputStream

         textstream = "com.sun.star.io.TextOutputStream"
         s_InfoTextOutputStream = x_MultiServiceFactory~createInstance(textstream)
         x_InfoActiveDataSource = s_InfoTextOutputStream~XActiveDataSource
         x_InfoActiveDataSource~setOutputStream(x_InfoPipeOutputStream)
         x_InfoTextOutputStream = s_InfoTextOutputStream~XTextOutputStream

         -- clear stream
         x_InfoPipeOutputStream~flush()

         crlf = "0d"x || "0a"x
         texttowrite = 'This Package was created by ExportLibrary macro by Josef Frysak' || crlf
         texttowrite = texttowrite || 'on ' || DATE("L") || ' at ' || TIME("C")
         x_InfoTextOutputStream~writeString(texttowrite)

         -- write into stream
         x_InfoPipeOutputStream~closeOutput()

         o_InfoPackageStream = x_HierarchicalNameAccess~getByHierarchicalName("PACKAGEINFO")
         x_InfoNameContainer = o_InfoPackageStream~XNameContainer

         o_InfoFileStream = x_PackageFactory~createInstanceWithArguments(fileargs)
         x_InfoActiveDataSink = o_InfoFileStream~XActiveDataSink

         x_InfoActiveDataSink~SetInputStream(x_InfoPipeInputStream)
         x_InfoNameContainer~insertByName("info.txt", o_InfoFileStream)

         -- if all changes are done, we write the data to the zipfile
         x_ChangesBatch = s_Package~XChangesBatch
         x_ChangesBatch~commitChanges()

      end

   end
   else
   do
      -- a message in case the selected library is not containing
      -- a parcel-descriptor file
      errortext = "Selected Directory is not a Library: no parcel-descriptor found "
      .bsf.dialog~messageBox(errortext, "ERROR", "error")
   end
   
end

-- a simple routine to parse the name of the file or the directory name
getLastFromURL:
   use arg url
   return RIGHT(url, LENGTH(url) - LASTPOS("/", url))

::requires UNO.CLS

Changelog

DateUserModification
2008-10-131Initial version

and