1
# Copyright 2004,2005 Pierre Martineau <pmartino@users.sourceforge.net>
2
# This file is part of bibOOo, a python package to manipulate
3
# bibliography in an OpenOffice.org writer document.
5
# bibOOo is part of Bibus a free software;
6
# you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
10
#/home/pmartino/Desktop/Bibus/bibus-cvs/bibus/bibOOo/bibOOoBase.py
11
# bibOOo is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with Bibus; if not, write to the Free Software
18
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
# this class implements basic interaction between a biliographic software and OOo
22
from __future__ import generators # py2.2, to be removed in python 2.3
25
# below we commented the normal way to call the class/constants
26
# the form used is to be compatible with cx_freeze
27
#from com.sun.star.connection import NoConnectException
28
NoConnectException = uno.getClass("com.sun.star.connection.NoConnectException")
29
#from com.sun.star.uno import RuntimeException
30
RuntimeException = uno.getClass("com.sun.star.uno.RuntimeException")
31
#from com.sun.star.lang import IllegalArgumentException, DisposedException
32
IllegalArgumentException = uno.getClass("com.sun.star.lang.IllegalArgumentException")
33
DisposedException = uno.getClass("com.sun.star.lang.DisposedException")
34
#from com.sun.star.io import IOException
35
IOException = uno.getClass("com.sun.star.io.IOException")
36
#from com.sun.star.container import NoSuchElementException
37
NoSuchElementException = uno.getClass("com.sun.star.container.NoSuchElementException")
38
#from com.sun.star.util import URL
39
URL = uno.getClass("com.sun.star.util.URL")
40
#from com.sun.star.text.ControlCharacter import PARAGRAPH_BREAK
41
PARAGRAPH_BREAK = uno.getConstantByName("com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK")
42
#from com.sun.star.beans import PropertyValue
43
PropertyValue = uno.getClass("com.sun.star.beans.PropertyValue")
44
#from com.sun.star.beans.PropertyState import DIRECT_VALUE
45
DIRECT_VALUE = uno.getConstantByName("com.sun.star.beans.PropertyState.DIRECT_VALUE")
46
#from com.sun.star.lang import Locale
47
Locale = uno.getClass("com.sun.star.lang.Locale")
49
#from com.sun.star.awt.FontSlant import ITALIC, NONE
51
ITALIC = uno.getConstantByName("com.sun.star.awt.FontSlant.ITALIC")
52
FontSlantNone = uno.getConstantByName("com.sun.star.awt.FontSlant.NONE")
53
#from com.sun.star.awt.FontWeight import BOLD, NORMAL
54
BOLD = uno.getConstantByName("com.sun.star.awt.FontWeight.BOLD")
55
NORMAL = uno.getConstantByName("com.sun.star.awt.FontWeight.NORMAL")
56
#from com.sun.star.awt.FontUnderline import SINGLE, NONE
57
#FontUnderlineNone = NONE
58
SINGLE = uno.getConstantByName("com.sun.star.awt.FontUnderline.SINGLE")
59
FontUnderlineNone = uno.getConstantByName("com.sun.star.awt.FontUnderline.NONE")
60
#from com.sun.star.style.CaseMap import UPPERCASE,SMALLCAPS, NONE
62
UPPERCASE = uno.getConstantByName("com.sun.star.style.CaseMap.UPPERCASE")
63
SMALLCAPS = uno.getConstantByName("com.sun.star.style.CaseMap.SMALLCAPS")
64
CaseMapNone = uno.getConstantByName("com.sun.star.style.CaseMap.NONE")
67
from bibOOo.CONST import *
69
class bibOOo_Error(Exception):
72
|-----bibOOo_NoConnect-----|
73
| |----bibOOo_NoOffice
74
| |----bibOOo_NoWriter
76
|-----bibOOo_ExecError-----|
77
|----bibOOo_PositionError
78
|----bibOOo_StyleError
82
def __init__(self,OOo=''):
83
self.OOo = OOo # we propagate the OOo error message in this attribute or an additional information
85
class bibOOo_NoConnect(bibOOo_Error):
86
"""Global class for connection error"""
87
msg = _("Cannot connect to Openoffice. See Documentation.")
88
class bibOOo_NoOffice(bibOOo_NoConnect):
89
"""We were not able to connect to a OOo instance"""
90
msg = _("Cannot connect to Openoffice. See Documentation.")
91
class bibOOo_NoWriter(bibOOo_NoConnect):
92
"""The top most OOo document is not a writer doc"""
93
msg = _("The front document in OOo must be a Writer document.")
95
class bibOOo_ExecError(bibOOo_Error):
96
"""Parent class for all error related to bibOOo specific problems"""
97
msg = _("Non allowed operation""")
98
class bibOOo_PositionError(bibOOo_ExecError):
99
"""We are trying to apply a function at a non suited position"""
100
msg = _("Incorrect position")
101
class bibOOo_StyleError(bibOOo_ExecError):
102
"""Error in the style file"""
103
msg = _("Style format Error")
104
class bibOOo_IOError(bibOOo_ExecError):
105
"""File error operation"""
106
msg = _("File error operation")
108
class bibOOo_Ref(object):
109
"""This class is a wrapper for OOo in-text citations
110
You can access the citation
111
as attributes : bibRef.Author etc...
112
Can be used to set or read citations in the current doc"""
114
def __init__(self,bibOOo_instance,OOoRef=None,ref=(),dbdict={}):
116
model is the document model in which we want to create the citation.
117
bibOOo_instance is needed only if OOoRef == None
118
OORef = "com.sun.star.text.TextField.Bibliography"
119
if OORef == None, we create a "com.sun.star.text.TextField.Bibliography"
121
a list/tuple = (identifier,BibliographicType,....,ISBN)
123
dbdict = dictionary = {'Identifier':'toto', 'BibliographicType':1, 'Address':'NY', 'Annote':'Note', ...}
124
the dbdict.keys() may be incomplete => Absent fields will be set to '', BibliographicType to 1 = ARTICLE
125
or an empty reference of type = 1 (ARTICLE)
126
then in all cases we wrap the OOo object
129
self.OOoRef = bibOOo_instance.model.createInstance("com.sun.star.text.TextField.Bibliography")
132
#tmp = [ PropertyValue(field,0,ref[OO_BIBLIOGRAPHIC_FIELDS[field]],DIRECT_VALUE) for field in OO_BIB_FIELDS ]
135
for field in OO_BIB_FIELDS:
136
try: tmp.append( PropertyValue(field,0,dbdict[field],DIRECT_VALUE) )
137
except KeyError: tmp.append( PropertyValue(field,0,'',DIRECT_VALUE) )
138
if 'BibliographicType' in dbdict.keys():
139
tmp[1] = PropertyValue('BibiliographicType',0,dbdict['BibliographicType'],DIRECT_VALUE) # to correct spelling error in OOo
140
if tmp[1].Value == '':
141
tmp[1] = PropertyValue('BibiliographicType',0,1,DIRECT_VALUE) # default type == ARTICLE
142
self.OOoRef.Fields = tuple(tmp)
144
#tmp = [ PropertyValue(field,0,'',DIRECT_VALUE) for field in OO_BIB_FIELDS ]
145
#tmp[1] = PropertyValue('BibiliographicType',0,1,DIRECT_VALUE) # ARTICLE
146
self.setRef( ('', 1, '', '', '','', '', '', '', '', '','', '', '', '', '', '', '','', '', '', '', '', '', '', '','', '', '', '', '') )
147
#self.OOoRef.Fields = tuple(tmp)
151
#def __eq__(self,other): # suppressed because it did not work in Ubuntu 7.10
152
# return self.Identifier == other.Identifier
154
#def __ne__(self,other):
155
# return self.Identifier != other.Identifier
157
def __getattr__(self,attr):
158
""" If it is a BIBLIOGRAPHIC_FIELDS, we return the value
159
otherwise, we return the attribute of the OORef
160
This way we can directly access the method of the OOo ref object """
161
if attr in OO_BIB_FIELDS:
162
return self.OOoRef.Fields[OO_BIBLIOGRAPHIC_FIELDS[attr]].Value
163
elif attr == 'BibliographicType': # spelling error in OOo
164
return self.OOoRef.Fields[1].Value
166
return getattr(self.OOoRef,attr)
168
def __setattr__(self,attr,value):
169
if attr in OO_BIB_FIELDS:
170
tmp = list(self.OOoRef.Fields)
171
tmp[OO_BIBLIOGRAPHIC_FIELDS[attr]] = PropertyValue(attr,0,value,DIRECT_VALUE)
172
self.OOoRef.Fields = tuple(tmp)
173
elif attr == 'BibliographicType': # spelling error in OOo
174
tmp = list(self.OOoRef.Fields)
175
tmp[1] = PropertyValue('BibiliographicType',0,value,DIRECT_VALUE)
176
self.OOoRef.Fields = tuple(tmp)
177
elif attr == 'OOoRef':
178
object.__setattr__(self,'OOoRef',value)
182
def setRef(self,ref):
184
Set the values of the reference using the data in
185
ref which is a list/tuple.
186
This is much faster than setting field by field
188
tmp = [ PropertyValue(field,0,ref[OO_BIBLIOGRAPHIC_FIELDS[field]],DIRECT_VALUE) for field in OO_BIB_FIELDS ]
189
self.OOoRef.Fields = tuple(tmp)
192
class bibOOoBase(object):
193
"""This is the main class to interact with OOo"""
194
# ------------------------ Connection setup ------------------------------
195
def __init__(self,con_type=1,host='localhost',port=8100,pipe='OOo_pipe'):
196
"""We connect to the running OOo instance
197
con_type = connection_type = 1 if pipe ; 0 if TCP
203
OO_CON_STR = "uno:socket,host=%s,port=%s;urp;StarOffice.ComponentContext"%(host,port)
205
OO_CON_STR = "uno:pipe,name=%s;urp;StarOffice.ComponentContext"%pipe
206
# get the uno component context from the PyUNO runtime
207
localContext = uno.getComponentContext()
208
# create the UnoUrlResolver
209
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext )
211
# connect to the running office
212
ctx = resolver.resolve( OO_CON_STR )
213
self.smgr = ctx.ServiceManager
214
# get the central desktop object
215
self.desktop = self.smgr.createInstanceWithContext( "com.sun.star.frame.Desktop",ctx)
217
self.transformer = MagicTransformer( ctx ) # this is to force PropertyValue.Value to the desired type because of a python bug
218
self.oTrans = self.smgr.createInstanceWithContext("com.sun.star.util.URLTransformer", ctx ) # used in __freezeBib to format URL
220
except NoConnectException, e:
221
raise bibOOo_NoOffice, e.Message
222
except IllegalArgumentException, e:
223
#print "The url is invalid (%s)" % e.Message
224
raise bibOOo_NoOffice, e.Message
225
except RuntimeException, e:
226
#print "An unknown error occured (%s)" % e.Message
227
raise bibOOo_NoOffice, e.Message
229
def connectToWriter(self, hilight = False, backColor = 0x00FFFF00, createBib = True, end = True):
230
"""connect to the top OOo document if it is a writer doc"""
231
self.bib = None # bibliographic index
233
self.model = self.desktop.getCurrentComponent()
234
if self.model and self.model.getImplementationName() == 'SwXTextDocument': # this is a text document
235
self.controller = self.model.getCurrentController()
236
self.cursor = self.controller.getViewCursor() # Current ViewCursor
237
# access the document's text property
238
self.text = self.model.Text
239
# look for the first bibliography index or create a new one at the end if no biblio index present
241
for i in range(self.model.getDocumentIndexes().getCount()):
242
self.bib = self.model.getDocumentIndexes().getByIndex(i)
243
if self.bib.getServiceName() == 'com.sun.star.text.Bibliography':
246
if not bibFound and createBib:
247
# we create the bibliography index at the end of the document
248
self.createIndex(end)
249
# we get the com.sun.star.text.FieldMaster.Bibliography after eventually creating it
251
self.tfm = self.model.getTextFieldMasters().getByName('com.sun.star.text.FieldMaster.Bibliography') # the biblio TextFieldMaster
252
except NoSuchElementException:
253
self.tfm = self.model.createInstance("com.sun.star.text.FieldMaster.Bibliography")
254
self.stylesList = self.model.getStyleFamilies() # styles set XIndexAccess (XStyleFamiliesSupplier interface)
255
self.__createBaseStyles() # create the styles if needed
256
self.hilightCitations(hilight, background = backColor) # hilight citations if required. Just change the CharStyle
257
#self.setIndexFormat() # set the biblio format REMOVED BECAUSE IT IS TOO SLOW !!!!
259
#print "You must have a text document opened in OpenOffice.org in oder to be able to use this menu"
260
raise bibOOo_NoWriter
261
except DisposedException,e:
262
raise bibOOo_NoOffice,e.Message
264
# ------------------------ iteration ------------------------------
266
for cit in self.getCitations(None):
269
# functions to get a sorted list of citations
270
def __isFused(self,x,y,cursor):
271
"""Return True if the two citations x & y are separated only by spaces => can be fused"""
273
cursor.gotoRange(x.Anchor.End,False)
274
if not x.Anchor.Text.compareRegionStarts(cursor,y.Anchor):
275
return True # we should not need it but it does not work if the two ranges start at the same position
276
cursor.gotoRange(y.Anchor.Start,True)
277
return not bool(cursor.String.strip(' ')) # if only white spaces between citations => we fuse them
278
#except IllegalArgumentException:
280
return False # we are not in the same Text or something goes wrong
282
def groupCitations(self,refs):
283
"""We group the citations in refs list.
284
We return a list of list.
285
Each list is a group of citations
286
i.e. citations separated by blank spaces"""
291
tmpcursor = lastref.Anchor.Text.createTextCursor()
293
if self.__isFused(lastref,ref,tmpcursor):
294
tmp_range.append(ref)
296
refs_out.append(tmp_range)
298
tmpcursor = ref.Anchor.Text.createTextCursor()
300
refs_out.append(tmp_range)
303
def getCitations(self,order=None):
304
"""Return a list of the citations ordered as
305
order == None : unsorted
306
order == index : order of the bibliographic index
307
order == document : order in the document
308
order == group : list of list. Order as document. When citations are consecutives they are in a sub-list.
309
Exemple: "Start doc [1] [2] continue [3] continue [4][5]" will give: [[1,2],[3],[4,5]]
311
# we first update the index and references.
312
#updateRef() # we update the references to be up-to-date
313
#refs = list(self.tfm.getPropertyValue('DependentTextFields')) # we get the references
314
refs = [ bibOOo_Ref(self,ref) for ref in self.tfm.getPropertyValue('DependentTextFields') ] # we get the references and wrap them in bibOOo_Ref objects
315
lbb = len(self.tfm.BracketBefore) # used later to get the numbers without the brackets
316
lba = -len(self.tfm.BracketAfter)
319
elif order == 'index':
320
SavedState = self.tfm.IsNumberEntries
321
self.tfm.IsNumberEntries = True # we number citations to get the order of them
322
self.model.getTextFields().refresh()
324
tmplist = [(int(x.getPresentation(False)[lbb:len(x.getPresentation(False))+lba]), x) for x in refs]
326
refs = [x for (key, x) in tmplist]
328
self.tfm.IsNumberEntries = SavedState # we reverse to the original state
331
# to sort by document:
332
# 1) We put for each ref a unique identifier (a number)
333
# 2) We ask OOo to sort by doc + numbers. As identifiers are uniques => each ref has its own number = order
334
# 3) We sort using the getPresentation(False)
335
# 4) We put back the correct identifiers
340
savedIdentifiers.append(ref.Identifier)
341
ref.Identifier = repr(i)
344
SavedState = self.tfm.IsNumberEntries, self.tfm.IsSortByPosition
345
self.tfm.IsNumberEntries = True
346
self.tfm.IsSortByPosition = True
347
self.model.getTextFields().refresh()
349
tmplist = [(int(x.getPresentation(False)[lbb:len(x.getPresentation(False))+lba]), x) for x in refs]
351
refs = [x for (key, x) in tmplist]
354
ref.Identifier = savedIdentifiers[int(ref.Identifier)]
356
self.model.getTextFields().refresh()
357
self.tfm.IsNumberEntries, self.tfm.IsSortByPosition = SavedState
358
if order == 'document': return refs
359
if order == 'group' : return self.groupCitations(refs) # order = 'group'
360
raise ValueError('What are we doing here? bibOOo line 357. order = %r is not a correct value.'%order)
361
# end of functions to get a sorted list of citations
365
# ------------------------ Index ------------------------------
366
def createIndex(self,end = True):
367
"""create bibliographic index at the end if True, or at the current cursor position if False"""
368
cursor = self.text.createTextCursor()
369
if end: cursor.gotoEnd(False) # we create at the end of the doc
370
else: cursor.gotoRange(self.cursor,False) # or at the view cursor
371
self.text.insertControlCharacter(cursor,PARAGRAPH_BREAK,False)
372
self.bib = self.model.createInstance("com.sun.star.text.Bibliography")
373
self.text.insertTextContent(cursor,self.bib,False)
374
if self.text.compareRegionEnds(self.cursor,cursor) == 0: # the viewcursor was at the end of the doc
375
self.cursor.gotoRange(self.bib.getAnchor().getStart(),False) # we must relocate it before the index
376
self.cursor.goLeft(1,False) # we are now just before the index
377
self.bib.update() # update the new index (title, etc.)
379
def updateIndex(self):
380
"""Update bibliography index"""
381
self.model.getTextFields().refresh() # refresh the fields in case citation format has changed
382
if self.bib: self.bib.update() # update de la biblio if it exists
384
def setIndexFormat(self,format):
386
set the format of the bibliographic index
387
format is a dictionary:
388
format.keys() = ['SortKeys', 'Title', 'Locale', 'IsNumberEntries', 'SortAlgorithm', 'IsSortByPosition', 'Bracket']
390
format['index']['Locale'] = 'en_US'
391
format['index']['Title'] = 'Bibliography'
392
format['index']['IsNumberEntries'] = True | False
393
format['index']['SortAlgorithm'] = 'alphanumeric'
394
format['index']['IsSortByPosition'] = True | False True = sorted in doc order ; False = sorted as in defined in SortKeys
395
format['index']['Bracket'] = '[]'
396
format['index']['SortKeys'] = ((4, True), (23, True)) = ( (field1,ascending),(field2,ascending), ... )
397
field1, field2 = zero based index of the field in CONST.OO_BIB_FIELDS ( 4 = Author ; 23 = Year )
400
format['ordering']['ARTICLE'] = tuple of tuple = ('text',text,style) | ('field',field_name,style) | ('tab',value,TabStopFillCharacter) | ('tab',None,TabStopFillCharacter)
401
where style = bibOOo_italic | bibOOo_bold ...
402
for tabs, if value = None => right aligned
403
exemple : ( ('field', u'Author', 0), ('text', u' (', 0), ('field', u'Year', 0), ('text', u')', 0) ) = Einstein (1920)
404
this must be defined for all the references types = BIB_TYPE
405
you can use format['ordering']['JOURNAL'] = format['ordering']['ARTICLE'] etc.. to save space
407
if not self.bib: return # if no bib, we it will crash
408
# set Bibliography service
409
self.bib.Locale = Locale(format['index']['Locale'][:2],format['index']['Locale'][-2:],'')
410
self.bib.SortAlgorithm = format['index']['SortAlgorithm']
411
self.bib.Title = format['index']['Title']
412
# set Bibliography FieldMaster
413
self.tfm.IsNumberEntries = bool(format['index']['IsNumberEntries'])
414
self.tfm.IsSortByPosition = bool(format['index']['IsSortByPosition'])
415
if format['index']['Bracket']:
416
self.tfm.BracketBefore = format['index']['Bracket'][0]
417
self.tfm.BracketAfter = format['index']['Bracket'][1]
419
self.tfm.BracketBefore = ''
420
self.tfm.BracketAfter = ''
421
# set Bibliography FieldMaster SortKeys
422
tmp = [ ( PropertyValue('SortKey',0,i[0],DIRECT_VALUE) , PropertyValue('IsSortAscending',0,bool(i[1]),DIRECT_VALUE) ) for i in format['index']['SortKeys'] ]
423
self.tfm.SortKeys = tuple(tmp)
424
# set Bibliography service LevelFormat (=fields ordering)
425
for reftype in BIB_TYPE:
427
for token in tuple(format['ordering'][reftype]):
428
if token[0] == 'text':
429
tmp.append((PropertyValue("TokenType",0,"TokenText",DIRECT_VALUE),\
430
PropertyValue("CharacterStyleName",0,self.__setStyleName(token[2]),DIRECT_VALUE),\
431
PropertyValue("Text",0,token[1],DIRECT_VALUE)))
432
elif token[0] == 'field':
433
tmp.append((PropertyValue("TokenType",0,"TokenBibliographyDataField",DIRECT_VALUE),\
434
PropertyValue("CharacterStyleName",0,self.__setStyleName(token[2]),DIRECT_VALUE),\
435
PropertyValue("BibliographyDataField",0,OO_BIBLIOGRAPHIC_FIELDS[token[1]],DIRECT_VALUE)))
436
elif token[0] == 'tab':
438
# PropertyValue("TabStopPosition",0,uno.Any('long',token[1]),DIRECT_VALUE), # does not work!
439
# the two following lines are a workaround for this bug.
440
special = PropertyValue("TabStopPosition",0,token[1],DIRECT_VALUE)
441
special = self.transformer.transform( special, "Value" , uno.Any( "long", token[1] ) )
442
tmp.append((PropertyValue("TokenType",0,"TokenTabStop",DIRECT_VALUE),\
444
PropertyValue("TabStopFillCharacter",0,token[2],DIRECT_VALUE),\
445
PropertyValue("CharacterStyleName",0,"",DIRECT_VALUE)))
447
tmp.append((PropertyValue("TokenType",0,"TokenTabStop",DIRECT_VALUE),\
448
PropertyValue("TabStopRightAligned",0,True,DIRECT_VALUE),\
449
PropertyValue("TabStopFillCharacter",0,token[2],DIRECT_VALUE),\
450
PropertyValue("CharacterStyleName",0,"",DIRECT_VALUE)))
452
raise bibOOo_StyleError, "Error in the style file: I can't understand a token like %r" %token.__repr__()
453
# the following two lines are a work around for bug #12504. See python-uno FAQ.
454
# since self.bib.LevelFormat.replaceByIndex(OO_BIBLIOGRAPHIC_TYPE[reftype]+1,tuple(tmp)) does not work
455
unoseq = uno.Any("[][]com.sun.star.beans.PropertyValue",tuple(tmp))
456
uno.invoke(self.bib.LevelFormat,"replaceByIndex",(BIBLIOGRAPHIC_TYPE[reftype]+1,unoseq))
457
# remark: +1 in the previous line since Index=1=ARTICLE, etc...
459
# ------------------------ CharStyles ------------------------------
460
def __createBaseStyles(self):
461
"""create base CharStyle for citations and index"""
462
charStyles = self.stylesList.getByName('CharacterStyles')
463
if not charStyles.hasByName(bibOOo_cit_baseCharStyleName):
464
self.createCharacterStyle(bibOOo_cit_baseCharStyleName,bibOOo_regular,bibOOo_normal,'')
465
if not charStyles.hasByName(bibOOo_index_baseCharStyleName):
466
self.createCharacterStyle(bibOOo_index_baseCharStyleName,bibOOo_regular,bibOOo_normal,'')
468
def __setStyleName(self,charstyle):
469
"""create a charStyle corresponding to charStyle if needed
470
return the style name as:
471
bibOOo_base<''|i><''|b><''|u><''|s|c> where i=italic, b=bold, u=underline, s=smallcaps, c=caps"""
472
# calculating style name
473
italic,bold,underline,caps = '','','',''
474
if charstyle & bibOOo_italic: italic = 'i'
475
if charstyle & bibOOo_bold: bold = 'b'
476
if charstyle & bibOOo_underline: underline = 'u'
477
if charstyle & bibOOo_caps: caps = 'c'
478
elif charstyle & bibOOo_smallcaps: caps = 's'
479
stylename = ''.join( (bibOOo_index_baseCharStyleName,italic,bold,underline,caps) ) # bibOOo_index_base ; bibOOo_index_basei ; etc...
480
# creating style if needed based on bibus_base
481
charStyles = self.stylesList.getByName('CharacterStyles')
482
if not charStyles.hasByName(stylename):
483
self.createCharacterStyle(stylename,charstyle,bibOOo_normal,bibOOo_index_baseCharStyleName)
486
def createCharacterStyle(self,charstylename,charstyle,position,parentstylename=''):
488
create an OOo CharacterStyle "com.sun.star.style.CharacterStyle" with the name charstylename if it does not exist
489
set its parent charstyle to parentstylename
490
set its value to style
491
where style is a combination of
492
from bibOOo_CONST import bibOOo_regular,bibOOo_italic,bibOOo_bold,bibOOo_caps,bibOOo_smallcaps,bibOOo_underline
493
from bibOOo_CONST import bibOOo_normal,bibOOo_exposant,bibOOo_indice
494
style = bibOOo_italic | bibOOo_bold = italic + bold
495
position = bibOOo_normal (=0) OR bibOOo_exposant (=1) OR bibOOo_indice (= -1)
497
charStyles = self.stylesList.getByName('CharacterStyles')
498
if not charStyles.hasByName(charstylename):
499
tmp_style = self.model.createInstance('com.sun.star.style.CharacterStyle') # create a char style
500
charStyles.insertByName(charstylename,tmp_style) # insert the style in the document
501
if parentstylename: tmp_style.setParentStyle(parentstylename) # set parent charstyle
502
# we save the default values default from newly created style
503
basePosture,baseWeight,baseUnderline,baseCaps = tmp_style.CharPosture, tmp_style.CharWeight, tmp_style.CharUnderline, tmp_style.CharCaseMap
504
# setting only the specific attributes
505
if charstyle & bibOOo_italic and basePosture != ITALIC: tmp_style.CharPosture = ITALIC
506
elif not charstyle & bibOOo_italic and basePosture == ITALIC: tmp_style.CharPosture = FontSlantNone
508
if charstyle & bibOOo_bold and baseWeight != BOLD: tmp_style.CharWeight = BOLD
509
elif not charstyle & bibOOo_bold and baseWeight == BOLD: tmp_style.CharWeight = NORMAL
511
if charstyle & bibOOo_underline and baseUnderline != SINGLE: tmp_style.CharUnderline = SINGLE
512
elif not charstyle & bibOOo_underline and baseUnderline == SINGLE: tmp_style.CharUnderline = FontUnderlineNone
514
if charstyle & bibOOo_caps and baseCaps != UPPERCASE: tmp_style.CharCaseMap = UPPERCASE
515
elif charstyle & bibOOo_smallcaps and baseCaps != SMALLCAPS: tmp_style.CharCaseMap = SMALLCAPS
516
elif not charstyle & bibOOo_caps and not charstyle & bibOOo_smallcaps and baseCaps!=CaseMapNone: tmp_style.CharCaseMap = CaseMapNone
517
# CharEscapement = 101 means automatique exposant ; -101 indice ; 0 normal
518
tmp_style.CharEscapement = 101 * position # automatic
519
if tmp_style.CharEscapement:
520
tmp_style.CharEscapementHeight = 58 # value ok in French. Other languages ?
522
tmp_style.CharEscapementHeight = 100
524
def updateCharacterStyle(self,charstylename,charstyle,position,parentstylename=''):
525
"""Reset values of style charstylename"""
526
charStyles = self.stylesList.getByName('CharacterStyles')
527
if charStyles.hasByName(charstylename):
528
tmp_style = charStyles.getByName(charstylename)
529
# reset all properties to default. Property list must be on alphabetical order!!!!
530
tmp_style.setPropertiesToDefault( ('CharCaseMap','CharEscapement','CharEscapementHeight','CharPosture','CharUnderline','CharWeight') )
531
if parentstylename: tmp_style.setParentStyle(parentstylename) # set parent charstyle
532
# we save the default values default from newly created style
533
basePosture,baseWeight,baseUnderline,baseCaps = tmp_style.CharPosture, tmp_style.CharWeight, tmp_style.CharUnderline, tmp_style.CharCaseMap
534
# setting only the specific attributes
535
if charstyle & bibOOo_italic and basePosture != ITALIC: tmp_style.CharPosture = ITALIC
536
elif not charstyle & bibOOo_italic and basePosture == ITALIC: tmp_style.CharPosture = FontSlantNone
538
if charstyle & bibOOo_bold and baseWeight != BOLD: tmp_style.CharWeight = BOLD
539
elif not charstyle & bibOOo_bold and baseWeight == BOLD: tmp_style.CharWeight = NORMAL
541
if charstyle & bibOOo_underline and baseUnderline != SINGLE: tmp_style.CharUnderline = SINGLE
542
elif not charstyle & bibOOo_underline and baseUnderline == SINGLE: tmp_style.CharUnderline = FontUnderlineNone
544
if charstyle & bibOOo_caps and baseCaps != UPPERCASE: tmp_style.CharCaseMap = UPPERCASE
545
elif charstyle & bibOOo_smallcaps and baseCaps != SMALLCAPS: tmp_style.CharCaseMap = SMALLCAPS
546
elif not charstyle & bibOOo_caps and not charstyle & bibOOo_smallcaps and baseCaps!=CaseMapNone: tmp_style.CharCaseMap = CaseMapNone
547
# CharEscapement = 101 means automatique exposant ; -101 indice ; 0 normal
548
tmp_style.CharEscapement = 101 * position # automatic
549
if tmp_style.CharEscapement:
550
tmp_style.CharEscapementHeight = 58 # value ok in French. Other languages ?
552
tmp_style.CharEscapementHeight = 100
555
def styleRef(self,ref,charstylename = bibOOo_cit_baseCharStyleName):
556
"""Set the CharStyle of the bibOOo_Ref object to charstylename"""
557
c = ref.Anchor.Text.createTextCursorByRange(ref.Anchor)
558
c.CharStyleName = charstylename
560
def hilightCitations(self,hilight = True, citStyleName = bibOOo_cit_baseCharStyleName, background = 0x00FFFF00):
562
Set the background of charStyle bibOOo_cit_baseCharStyleName
563
to background (default = yellow)
565
elif hilight = False => background = Default
567
charStyles = self.stylesList.getByName('CharacterStyles')
568
tmp_style = charStyles.getByName(bibOOo_cit_baseCharStyleName)
570
tmp_style.CharBackColor = background # background (default = yellow)
572
tmp_style.setPropertyToDefault('CharBackColor') # normal background
574
def resetCitationStyle(self,charstylename = bibOOo_cit_baseCharStyleName):
576
Reset the style of all the citations to bibOOo_cit_baseCharStyleName
577
This is needed if some citations have been inserted by another means than
578
bibOOo, for instance when the user has used the classical OOo interface.
581
c = ref.Anchor.Text.createTextCursorByRange(ref.Anchor)
582
c.CharStyleName = charstylename # reset the style it case it has changed
584
# ------------------------ Citations ------------------------------
585
def insertRef(self,ref,charstylename = bibOOo_cit_baseCharStyleName):
586
"""bibOOo_Ref object => insert at the current cursor position
587
using CharStyle charstylename
589
if self.notInBibIndex(self.cursor):
590
c = self.cursor.Text.createTextCursorByRange(self.cursor) # Add at cursor location (replace selection)
591
c.CharStyleName = charstylename
592
c.Text.insertTextContent(c,ref.OOoRef,True)
593
self.cursor.setPropertyToDefault('CharStyleName') # reset cursor to default
595
raise bibOOo_PositionError,"Try to insert a reference in the Bibliographic index"
597
def createRef(self,ref=(),dbdict={}):
599
create a bibOOo_Ref object from
600
a tuple/list = (identifier,BibliographicType,....,ISBN)
601
return an empty ARTICLE if ref=()
603
return bibOOo_Ref(self,None,ref,dbdict)
605
# ------------------------ Freezing ------------------------------
606
def __fuse_range(self,numbers,cit_rangesep='-'):
607
"""numbers is a sorted list of integers.
608
We return a list of strings where 1,2,3 => '1(cit_rangesep)3' """
609
tmpranges,tmp = [],[]
611
for i in xrange(1,len(numbers)):
612
if numbers[i] == numbers[i-1] + 1:
613
tmp.append(numbers[i])
617
tmpranges.append("%s-%s"%(tmp[0],tmp[-1])) # we fuse
619
tmpranges.extend(map(lambda x:repr(x),tmp))
622
tmpranges.append("%s%s%s"%(tmp[0],cit_rangesep,tmp[-1])) # we fuse
624
tmpranges.extend(map(lambda x:repr(x),tmp))
627
def __freezeNumberedCitations(self,messages = lambda i,x:sys.stdout.write('%s\n'%x),cit_sort=True,cit_fuse=True,cit_range=True,cit_separator='; ',cit_rangesep='-'):
629
format the in-text citations (sort,range,style, etc..)
631
depending on cit_sort,cit_fuse,cit_range we replace
632
[1] [3][2][5] => [1-3,5] etc...
634
apply(messages, (.7,msg7 ))
635
if not cit_fuse and not cit_sort:
636
for ref in self: # we don't mind about the order
637
c = ref.Anchor.Text.createTextCursorByRange(ref.Anchor.End)
638
ref.Anchor.Text.insertString(c,ref.getPresentation(0),True)
640
refranges = self.getCitations(order='group')
641
for refs in refranges:
642
c = refs[0].Anchor.Text.createTextCursorByRange(refs[0].Anchor.End) # cursor at end
643
bb = self.tfm.BracketBefore
644
ba = self.tfm.BracketAfter
647
numbers = [ int(x.getPresentation(False)[lbb:len(x.getPresentation(False))+lba]) for x in refs ]
650
ranges = self.__fuse_range(numbers,cit_rangesep) # calculate ranges
652
ranges = [repr(x) for x in numbers]
654
print "What are we doing here. bibOOo line 492"
655
# we insert in the text
656
refs[0].Anchor.Text.insertString(c,"%s%s%s" %(bb,cit_separator.join(ranges),ba),True)
658
def __freezeIdentifierCitations(self,messages = lambda i,x:sys.stdout.write('%s\n'%x),cit_fuse=True,cit_separator='; '):
661
we just copy/paste the identifiers with fusion if cit_fuse = True
663
apply(messages, (.7,msg7 ))
665
for ref in self: # we don't mind about the order
666
c = ref.Anchor.Text.createTextCursorByRange(ref.Anchor.End)
667
ref.Anchor.Text.insertString(c,ref.getPresentation(0),True)
669
refranges = self.getCitations(order='group')
670
for refs in refranges:
671
c = refs[0].Anchor.Text.createTextCursorByRange(refs[0].Anchor.End) # cursor at end
672
bb = self.tfm.BracketBefore
673
ba = self.tfm.BracketAfter
676
identifiers = [x.getPresentation(False)[lbb:len(x.getPresentation(False))+lba] for x in refs]
677
# we insert in the text
678
refs[0].Anchor.Text.insertString(c,"%s%s%s" %(bb,cit_separator.join(identifiers),ba),True)
680
def freezeCitations(self,messages = lambda i,x:sys.stdout.write('%s\n'%x),cit_sort=True,cit_fuse=True,cit_range=True,cit_separator='; ',cit_rangesep='-'):
682
format the in-text citations (sort,range,style, etc..)
684
depending on cit_sort,cit_fuse,cit_range we replace
685
[1] [3][2][5] => [1-3,5] etc...
687
we just copy/paste the identifiers with fusion if cit_fuse = True
689
# we first freeze the citations
690
if self.tfm.IsNumberEntries:
691
self.__freezeNumberedCitations(messages,cit_sort,cit_fuse,cit_range,cit_separator,cit_rangesep)
693
self.__freezeIdentifierCitations(messages,cit_fuse,cit_separator)
694
self.freezeIndex() # we freeze the index
695
self.tfm.dispose() # we remove all the citations
697
def freezeIndex(self):
699
make a copy of the bibliographic index, then remove the index
700
Freeze the index by copying then pasting it.
702
#Cut = '.uno:Cut' # 'slot:5710' # slot values. May change in the future ?
703
Copy = '.uno:Copy' # 'slot:5711'
704
Paste = '.uno:Paste' # 'slot:5712'
705
self.cursor.gotoRange(self.bib.Anchor,False) # select the bib
707
oUrl.Complete = Copy # copy the current selection
708
countOfUrls,parsedUrl = self.oTrans.parseSmart( oUrl, ".uno" )
709
oDisp = self.controller.queryDispatch( parsedUrl, "", 0 )
711
oDisp.dispatch(parsedUrl,())
712
# Move The cursor After the index
713
self.cursor.collapseToEnd()
714
self.cursor.goRight(1,False)
715
# Then paste the index
716
oUrl.Complete = Paste # paste the clipboard
717
countOfUrls,parsedUrl = self.oTrans.parseSmart( oUrl, ".uno" )
718
oDisp = self.controller.queryDispatch( parsedUrl, "", 0 )
720
oDisp.dispatch(parsedUrl,())
721
self.text.insertControlCharacter(self.cursor,PARAGRAPH_BREAK,False)
726
"""Save the current doc if needed, then create a new one = copy"""
727
if self.model.isModified():
728
raise bibOOo_IOError,"You must first save the current document"
729
if self.model.hasLocation():
732
raise bibOOo_IOError,"Impossible to save the current document"
733
# we store the old name
734
name = self.model.getURL()
737
countOfUrls,parsedUrl = self.oTrans.parseSmart( oURL, "http" )
739
name = os.path.splitext(parsedUrl.Name)[0]
743
# self.model.storeAsURL(self.model.getLocation(),())
745
# raise bibOOo_IOError,"Impossible to save the current document"
747
fa = self.smgr.createInstance('com.sun.star.ucb.SimpleFileAccess')
748
inputstream = fa.openFileRead(self.model.getLocation())
749
pvDescriptor=(PropertyValue('InputStream',0,inputstream,DIRECT_VALUE),
750
PropertyValue('Hidden',0,True,DIRECT_VALUE))
751
self.model = self.desktop.loadComponentFromURL('private:stream', "_default",0,pvDescriptor) # reload the document from stream
752
self.controller = self.model.getCurrentController()
753
self.cursor = self.controller.getViewCursor() # Current ViewCursor
754
self.text = self.model.Text
755
# look for the first bibliography index or create a new one at the end if no biblio index present
756
for i in range(self.model.getDocumentIndexes().getCount()):
757
self.bib = self.model.getDocumentIndexes().getByIndex(i)
758
if self.bib.getServiceName() == 'com.sun.star.text.Bibliography':
760
# we get the com.sun.star.text.FieldMaster.Bibliography after eventually creating it
762
self.tfm = self.model.getTextFieldMasters().getByName('com.sun.star.text.FieldMaster.Bibliography') # the biblio TextFieldMaster
763
except NoSuchElementException:
764
self.tfm = self.model.createInstance("com.sun.star.text.FieldMaster.Bibliography")
765
self.stylesList = self.model.getStyleFamilies() # styles XIndexAccess (XStyleFamiliesSupplier interface)
766
# we define a name and we but it in the DocumentInfo Title => in the Windows title
767
self.model.DocumentInfo.Title='%s-formatted' %name
771
def finalize(self,messages = lambda i,x:sys.stdout.write('%s\n'%x),**kwds):
773
finalize(self,cit_sort=True,cit_fuse=True,cit_range=True,cit_separator='; ')
774
make a copy of the current doc
775
make a copy of the bibliographic index, then remove the index
776
format the in-text citations (sort,range,style, etc..)
777
we print formatting messages in it
778
Default = None = stdout
780
apply(messages, (.1,msg1) )
781
if not self.__newDoc(): # we try to open a copy of the current doc.
782
raise bibOOo_IOError,"Cannot save the current document" # error if not possible
783
apply(messages, (.2,msg2) )
784
self.__createBaseStyles() # create the citation base style if needed
785
apply(messages, (.3,msg3) )
786
self.hilightCitations(False) # we don't want to hilight for the final format
787
self.resetCitationStyle() # reset the style for the citations
788
# needed to 'freeze' the Anchors because of a bug in OOo ?
789
#fixAnchors = [ref.Anchor for ref in self.getCitations(order=None)] # bug OOo ?
791
# self.updateRef() # make ref uptodate
792
apply(messages, (.4,msg4) )
793
if not self.bib: self.createIndex() # we create the index if needed
794
self.updateIndex() # update index
795
self.freezeCitations(messages = messages,**kwds)
796
apply(messages, (.9,msg5) )
797
self.controller.Frame.ContainerWindow.setVisible(True) # make the new frame visible
798
self.controller.Frame.ComponentWindow.setVisible(True) # make the new doc visible
799
self.model.setModified(False) # disable the save button/toolbar icon
800
apply(messages, (1.0,msg6) )
802
# ------------------------ Divers ------------------------------
803
def saveDoc(self,url=None):
805
Store the current doc.
806
if url != None, we use it
807
Otherwise we save using the current location
810
if self.model.hasLocation():
813
raise bibOOo_IOError,"Impossible to save the current document"
815
if url.endswith(".sxw"):
816
pd = (PropertyValue("FilterName",0,"StarOffice XML (Writer)",DIRECT_VALUE),)
817
elif url.endswith(".odt"):
818
pd = (PropertyValue("FilterName",0,"writer8",DIRECT_VALUE),)
819
else: # default format
822
self.model.storeAsURL(uno.systemPathToFileUrl(url),pd)
824
self.model.storeAsURL(uno.systemPathToFileUrl(url),()) # if it fails, we use default format
827
"""Give focus to the current OOo document"""
828
frame = self.desktop.getCurrentFrame().getContainerWindow()
831
def notInBibIndex(self,cursor):
832
"Return True if the range does not intercept with the Bibliographic index"
833
if self.bib != None and cursor.Text == self.bib.Anchor.Text: # must be in the same Text to be compared
834
curs = cursor.Text.createTextCursorByRange(cursor)
836
b=cursor.Text.compareRegionStarts(curs.Start,self.bib.Anchor.End) != 1 # cursor after Bibliography index
838
curs.goRight(1,False)
839
a=cursor.Text.compareRegionEnds(curs.End,self.bib.Anchor.Start) != -1 # cursor before Bibliography index
842
return True # it is not in the same Text and cannot be compared
844
# the following code is a workaround to a python-uno bug that makes PropertyValue().Value=uno.Any('long',100) not possible.
845
# many thanks to Joerg Budischewski for this code.
846
# this is used to set "TabStopPosition" in the Bibliographic index
847
class MagicTransformer:
848
def __init__( self , ctx ):
849
self.inv = ctx.ServiceManager.createInstanceWithContext(
850
"com.sun.star.script.Invocation", ctx )
851
self.insp = ctx.ServiceManager.createInstanceWithContext(
852
"com.sun.star.beans.Introspection", ctx )
853
def transform( self, struct , propName, value ):
854
myinv = self.inv.createInstanceWithArguments( (struct,) )
855
access = self.insp.inspect( myinv )
856
method = access.getMethod( "setValue" , -1 )
857
uno.invoke( method, "invoke", ( myinv, ( propName , value ) ))
858
method = access.getMethod( "getMaterial" , -1 )
859
ret,dummy = method.invoke(myinv,() )