ooRexx library export addon Josef Frysak How to create an addon out of an ooRexx library?

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.

-- 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 = "{%see com.sun.star.frame.Desktop}" s_Desktop = x_ComponentContext~getServiceManager~{%see com.sun.star.lang.XMultiServiceFactory%XMultiServiceFactory}~createInstance(service) x_Desktop = s_Desktop~{%see com.sun.star.frame.XDesktop%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()~{%see com.sun.star.lang.XMultiServiceFactory%XMultiServiceFactory} folderpicker = "{%see com.sun.star.ui.dialogs.OfficeFolderPicker}" s_FolderDialog = x_MultiServiceFactory~createInstance(folderpicker) x_FolderDialog = s_FolderDialog~{%see com.sun.star.ui.dialogs.XFolderPicker%XFolderPicker} -- better name for our dialog: x_FolderDialog~setDescription("Select User Library to Export") -- get Path to user Macros s_pathsubst = x_MultiServiceFactory~createInstance("{%see com.sun.star.util.PathSubstitution}") x_stringsubst = s_pathsubst~{%see com.sun.star.util.XStringSubstitution%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("{%see com.sun.star.ucb.SimpleFileAccess}") x_SimpleFileAccess = s_SimpleFileAccess~{%see com.sun.star.ucb.XSimpleFileAccess%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("{%see com.sun.star.packages.Package}") x_PackageInit = s_Package~{%see com.sun.star.lang.XInitialization%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~{%see com.sun.star.container.XHierarchicalNameAccess%XHierarchicalNameAccess} -- get the root item and its containerinterface o_RootPackageStream = x_HierarchicalNameAccess~getByHierarchicalName("") x_RootNameContainer = o_RootPackageStream~{%see com.sun.star.container.XNameContainer%XNameContainer} -- now create a factory which is able to create new subdirectories and files x_PackageFactory = s_Package~{%see com.sun.star.lang.XSingleServiceFactory%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~{%see com.sun.star.container.XNameContainer%XNameContainer} -- make this directory an ooRexx script library x_LibraryPropertySet = o_LibraryPackageStream~{%see com.sun.star.beans.XPropertySet%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~{%see com.sun.star.io.XActiveDataSink%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("{%see com.sun.star.io.Pipe}") x_InfoPipeOutputStream = s_InfoPipe~{%see com.sun.star.io.XOutputStream%XOutputStream} x_InfoPipeInputStream = s_InfoPipe~{%see com.sun.star.io.XInputStream%XInputStream} textstream = "{%see com.sun.star.io.TextOutputStream}" s_InfoTextOutputStream = x_MultiServiceFactory~createInstance(textstream) x_InfoActiveDataSource = s_InfoTextOutputStream~{%see com.sun.star.io.XActiveDataSource%XActiveDataSource} x_InfoActiveDataSource~setOutputStream(x_InfoPipeOutputStream) x_InfoTextOutputStream = s_InfoTextOutputStream~{%see com.sun.star.io.XTextOutputStream%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~{%see com.sun.star.container.XNameContainer%XNameContainer} o_InfoFileStream = x_PackageFactory~createInstanceWithArguments(fileargs) x_InfoActiveDataSink = o_InfoFileStream~{%see com.sun.star.io.XActiveDataSink%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~{%see com.sun.star.util.XChangesBatch%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
Initial version