Skip to content

Instantly share code, notes, and snippets.

Created Oct 1, 2017
What would you like to do?
a python UNO code I used to format my student papers.
import uno
import os
# that's like a consts, but they isn't since consts not allowed in python 😝
HEADING1 = "Heading 1"
HEADING2 = "Heading 2"
HEADING5 = "Heading 5" #appendinx
STYLESFILE = "./styles.odt"
PAGE_BEFORE = 4 #that is from enumeration — that awful API have problems with them
def rmLastEmptyLine(paragraph):
cursor = paragraph.Text.createTextCursor() #it is created at start of document, not paragraph
cursor.gotoRange(paragraph.End, False) #get end of the current paragraph
if cursor.String.endswith('\n'):
cursor.String = cursor.String[:-1] #strip last newline
def overwriteStyles(document, fromFile):
"""First arg is the document itself, the second is a string with path to style file in UNO API format"""
styles = document.StyleFamilies
styles.loadStylesFromURL(fromFile, styles.StyleLoaderOptions)
def addNumberingSomeHeading1n2s(text, h1TillBiblio=None, h1n2Numbered=None):
enumeration = text.createEnumeration()
heading1s = 0 #«2» is intro; «5» is 3-rd chapter; «7» is biblio
while enumeration.hasMoreElements():
par = enumeration.nextElement()
if ( par.supportsService("") and
par.ParaStyleName != None):
if par.ParaStyleName == HEADING1:
heading1s = heading1s + 1
if ( heading1s <= 6 #till, but excluding biblio
and h1TillBiblio != None):
if (par.ParaStyleName == HEADING1 or
par.ParaStyleName == HEADING2):
if (heading1s > 5 or heading1s == 1 or heading1s == 2):
par.setPropertyValue("NumberingStyleName", "NONE")
par.setPropertyValue("NumberingStyleName", "Numbering 1")
if h1n2Numbered != None:
if heading1s >= 8: #fuck this shit
par.setPropertyValue("BreakType", 0) #remove page break
if (heading1s == 7 and par.ParaStyleName == HEADING5): #just after the biblio, the first appendix
par.setPropertyValue("BreakType", PAGE_BEFORE)
def insertNewlineAfterPar(par):
cursor = par.Text.createTextCursor() #it is created at start of document, not paragraph!
cursor.gotoRange(par.End, False) #get end of the current paragraph
#cursor.goRight(1, False)
cursor.String = "\n"
def insertSpaceStartPar(par):
cursor = par.Text.createTextCursor() #it is created at start of document, not paragraph!
cursor.gotoRange(par.Start, False) #get start of the current paragraph
cursor.String = " "
def absoluteUrl(relativeFile):
"""Constructs absolute path to the current dir in the format required by PyUNO that working with files"""
return "file:///" + os.path.realpath(".") + "/" + relativeFile
def parBreak(document, cursor):
"""Inserts a paragraph break at cursor position"""
document.Text.insertControlCharacter( cursor.End,
def updateTOC(document):
"""Update links in table of contents"""
iList = document.getDocumentIndexes()
assert(iList.getCount() > 0), "Table of contents not found, aborting!"
for i in range(0, iList.getCount()):
def setFirstPage(file):
"""Sets the first page style to «First Page»"""
enumeration = file.Text.createEnumeration()
enumeration.nextElement().PageDescName = 'First Page'
#connect to office, and get the file object
localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext(
"", localContext )
smgr = resolver.resolve( "uno:socket,host=localhost,port=8100;urp;StarOffice.ServiceManager" )
remoteContext = smgr.getPropertyValue( "DefaultContext" )
desktop = smgr.createInstanceWithContext( "",remoteContext)
file = desktop.loadComponentFromURL(absoluteUrl("./output/output.odt") ,"_blank", 0, ())
overwriteStyles(file, absoluteUrl(STYLESFILE))
#insert at the beginning the file with Chapter1
cursor = file.Text.createTextCursor()
#to not screw the first paragraph formatting let's first make an empty one here
parBreak(file, cursor)
cursor.insertDocumentFromURL(absoluteUrl("./Ch1.odt"), ())
addNumberingSomeHeading1n2s(file.Text, insertNewlineAfterPar, insertSpaceStartPar)
updateTOC(file) #the inserted TOC needs to be updated
#save the file
print("Not implemented: removing Appendinx entries from the end of TOC")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment