Printing selected sheets and ranges

From Apache OpenOffice Wiki
Jump to: navigation, search

This script was published by Villeroy at the Code Snippets Forum.

Villeroy quote
The attached Python code provides 2 routines. One prints the current selection of (multiple) cell range(s), the other one prints the used ranges of the selected sheet(s).

Original code

import uno
from com.sun.star.uno import RuntimeException
 
def getUsedAddress(oSheet):
    '''com.sun.star.table.CellRangeAddress of a sheet's used range'''
    oRg = oSheet.createCursor()
    oRg.gotoStartOfUsedArea(False)
    oRg.gotoEndOfUsedArea(True)
    return oRg.getRangeAddress()
 
def clearPrintAreas(doc):
    '''remove all print areas from a Calc document'''
    esh = doc.Sheets.createEnumeration()
    while esh.hasMoreElements():
        sh = esh.nextElement()
        sh.setPrintAreas(tuple())
 
def getPrintAreasDict(doc):
    '''return a dict of sheet indices with print areas'''
    d = {}
    esh = doc.Sheets.createEnumeration()
    while esh.hasMoreElements():
        sh = esh.nextElement()
        n = sh.RangeAddress.Sheet
        d[n]= sh.getPrintAreas()
    return d
 
def setPrintAreasByDict(doc, d, bWholeSheet):
    for k,v in d.items():
        sh = doc.Sheets.getByIndex(k)
        if bWholeSheet:
            v = (getUsedAddress(sh),)
        sh.setPrintAreas(v)
 
def getTmpURL():
    import unohelper, os
    f = os.tmpnam() +'.pdf'
    return unohelper.systemPathToFileUrl(f)
 
def getDictFromAddresses(tpla):
    '''Split tuple of addresses into dict of sheet indices.'''
    d = {}
    for i in tpla:
        ish = i.Sheet
        if not d.has_key(ish):
            d[ish] = [i,]
        else:
            d[ish].append(i)
 
    for k,v in d.items():
        d[k] = tuple(v)
 
    return d
 
def printSelectedCells():
    '''Print current selection of (multiple) cell range(s)'''
    printSomething(False)
 
def printSelectedSheets():
    '''Print used ranges of currently selected sheets'''
    printSomething(True)
 
def printSomething(bWholeSheet):
    doc = XSCRIPTCONTEXT.getDocument()
    sel = doc.getCurrentSelection()
 
    # Let's support c.s.s.sheet.SheetCellRanges collection.
    # The intersection of a range with its own address
    # gives a collection having that single range
    if sel.supportsService('com.sun.star.sheet.SheetCellRange'):
        sel = sel.queryIntersection(sel.getRangeAddress())
    elif sel.supportsService('com.sun.star.sheet.SheetCellRanges'):
        a = sel.getRangeAddresses()
    else:
        raise(Exception, 'NO RANGE SELECTION')
 
    # back up current print areas
    d1 = getPrintAreasDict(doc)
    clearPrintAreas(doc)
 
    d2 = getDictFromAddresses(a)
    setPrintAreasByDict(doc, d2, bWholeSheet)
 
    p = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
    p.Name = 'FileName'
    p.Value = getTmpURL()
    doc.com_sun_star_view_XPrintable_print((p,))
 
    clearPrintAreas(doc)
    setPrintAreasByDict(doc, d1, False)
 
g_exportedScripts = printSelectedCells, printSelectedSheets,

Process of the script

The script perform the following tasks:

  1. Loop through the sheets collection and load the print ranges them in a variable.
  2. Remove them
  3. Change the selected ranges into print ranges
  4. Store the ranges into a temporary PDF
  5. Clear the print ranges
  6. Restore the original print ranges

The script first create the functions we will perform on the printSomething() function. We generate 5 functions that will manipulate the Print Ranges and finally call them up on the final function.

Calling the API

We make aware that our Python code will use the UNO API by importing the Module UNO and RuntimeException. The RuntimeException depends from the uno module. It help us signal an error, which was not covered by the interface method specification. Meaning that we will use this to have extra error handling features.

import uno
from com.sun.star.uno import RuntimeException

Load print ranges

We start by grabbing the area from the Calc page using the com.sun.star.table.CellRangeAddress, establish the start and end of the used area and return the total range of cells.

def getUsedAddress(oSheet):
    '''com.sun.star.table.CellRangeAddress of a sheet's used range'''
    oRg = oSheet.createCursor()
    oRg.gotoStartOfUsedArea(False)
    oRg.gotoEndOfUsedArea(True)
    return oRg.getRangeAddress()

Clear print ranges

This function reset the cell range using the createEnumeration() function and doing a loop until the end.

def clearPrintAreas(doc):
    '''remove all print areas from a Calc document'''
    esh = doc.Sheets.createEnumeration()
    while esh.hasMoreElements():
        sh = esh.nextElement()
        sh.setPrintAreas(tuple())

Create print ranges

Here we use two functions:

  • Get the print area with a dictionary
  • Set the print area with a dictionary

We generate a dictionary then we load it with a createEnumeration() and a loop to go to the next element within the Range on the sheet.

For the setting the print area you do a getByIndex() a conditional that goes through the dictionary in d and use the getUsedAddress() function.

def getPrintAreasDict(doc):
    '''return a dict of sheet indices with print areas'''
    d = {}
    esh = doc.Sheets.createEnumeration()
    while esh.hasMoreElements():
        sh = esh.nextElement()
        n = sh.RangeAddress.Sheet
        d[n]= sh.getPrintAreas()
    return d
 
def setPrintAreasByDict(doc, d, bWholeSheet):
    for k,v in d.items():
        sh = doc.Sheets.getByIndex(k)
        if bWholeSheet:
            v = (getUsedAddress(sh),)
        sh.setPrintAreas(v)

Print as PDF

We use this function to drop the data information into a temporary file. We generate the name into os.tmpnam() and add the .pdf extension, loading it into f. Then we use the unohelper.systemPathToFile() and load the f variable.

def getTmpURL():
    import unohelper, os
    f = os.tmpnam() +'.pdf'
    return unohelper.systemPathToFileUrl(f)

Clear the ranges

We use the tuple into a function that will go through it and pass it to a dictionary which will separate the value and the index.

def getDictFromAddresses(tpla):
    '''Split tuple of addresses into dict of sheet indices.'''
    d = {}
    for i in tpla:
        ish = i.Sheet
        if not d.has_key(ish):
            d[ish] = [i,]
        else:
            d[ish].append(i)
 
    for k,v in d.items():
        d[k] = tuple(v)
 
    return d

Making it all work

For these steps we first call the document, and the service to manipulate the Cell Ranges within. Then we execute the functions we previously wrote.

We could subdivide this script into:

  • Getting the current document
  • Instantiating the service com.sun.star.sheet.SheetCellRange
  • We verify that the cell range is defined otherwise use an aditional function queryIntersection()
  • We backup the print area with the functions getPrintAreaDict() and getDictFromAddresses()
  • We dump the information on our temporary file and fill the properties using com.sun.star.beans.PropertyValue
  • We finalize by using the XPrint service and provide the setPrintAreasByDict() and supply them with the print areas
def printSomething(bWholeSheet):
    doc = XSCRIPTCONTEXT.getDocument()    sel = doc.getCurrentSelection()
    # Let's support c.s.s.sheet.SheetCellRanges collection.
    # The intersection of a range with its own address
    # gives a collection having that single range
    if sel.supportsService('com.sun.star.sheet.SheetCellRange'):
        sel = sel.queryIntersection(sel.getRangeAddress())
    elif sel.supportsService('com.sun.star.sheet.SheetCellRanges'):
        a = sel.getRangeAddresses()
    else:
        raise(Exception, 'NO RANGE SELECTION')
 
    # backup current print areas
    d1 = getPrintAreasDict(doc)
    clearPrintAreas(doc)
    d2 = getDictFromAddresses(a)
    setPrintAreasByDict(doc, d2, bWholeSheet)
 
    p = uno.createUnoStruct('com.sun.star.beans.PropertyValue')
    p.Name = 'FileName'
    p.Value = getTmpURL()
 
    doc.com_sun_star_view_XPrintable_print((p,))
    clearPrintAreas(doc)
    setPrintAreasByDict(doc, d1, False)
Personal tools