Home | Trees | Indices | Help |
|
---|
|
1 # -*- coding: latin-1 -*- 2 """GNUmed forms classes 3 4 Business layer for printing all manners of forms, letters, scripts etc. 5 6 license: GPL v2 or later 7 """ 8 #============================================================ 9 __author__ ="Ian Haywood <ihaywood@gnu.org>, karsten.hilbert@gmx.net" 10 11 12 import os 13 import sys 14 import time 15 import os.path 16 import logging 17 import codecs 18 import re as regex 19 import shutil 20 import random 21 import platform 22 import subprocess 23 import socket # needed for OOo on Windows 24 #, libxml2, libxslt 25 import shlex 26 27 28 if __name__ == '__main__': 29 sys.path.insert(0, '../../') 30 from Gnumed.pycommon import gmI18N 31 gmI18N.activate_locale() 32 gmI18N.install_domain(domain = 'gnumed') 33 from Gnumed.pycommon import gmTools 34 from Gnumed.pycommon import gmDispatcher 35 from Gnumed.pycommon import gmExceptions 36 from Gnumed.pycommon import gmMatchProvider 37 from Gnumed.pycommon import gmBorg 38 from Gnumed.pycommon import gmLog2 39 from Gnumed.pycommon import gmMimeLib 40 from Gnumed.pycommon import gmShellAPI 41 from Gnumed.pycommon import gmCfg 42 from Gnumed.pycommon import gmCfg2 43 from Gnumed.pycommon import gmBusinessDBObject 44 from Gnumed.pycommon import gmPG2 45 46 from Gnumed.business import gmPerson 47 from Gnumed.business import gmStaff 48 from Gnumed.business import gmPersonSearch 49 from Gnumed.business import gmPraxis 50 51 52 _log = logging.getLogger('gm.forms') 53 54 #============================================================ 55 # this order is also used in choice boxes for the engine 56 form_engine_abbrevs = [u'O', u'L', u'I', u'G', u'P', u'A', u'X', u'T'] 57 58 form_engine_names = { 59 u'O': 'OpenOffice', 60 u'L': 'LaTeX', 61 u'I': 'Image editor', 62 u'G': 'Gnuplot script', 63 u'P': 'PDF forms', 64 u'A': 'AbiWord', 65 u'X': 'Xe(La)TeX', 66 u'T': 'text export' 67 } 68 69 form_engine_template_wildcards = { 70 u'O': u'*.o?t', 71 u'L': u'*.tex', 72 u'G': u'*.gpl', 73 u'P': u'*.pdf', 74 u'A': u'*.abw', 75 u'X': u'*.tex', 76 u'T': u'*.ini' 77 } 78 79 # is filled in further below after each engine is defined 80 form_engines = {} 81 82 #============================================================ 83 # match providers 84 #============================================================8699 #============================================================88 89 query = u""" 90 SELECT 91 name_long AS data, 92 name_long AS list_label, 93 name_long AS field_label 94 FROM ref.v_paperwork_templates 95 WHERE name_long %(fragment_condition)s 96 ORDER BY list_label 97 """ 98 gmMatchProvider.cMatchProvider_SQL2.__init__(self, queries = [query])101114 #============================================================103 104 query = u""" 105 SELECT 106 name_short AS data, 107 name_short AS list_label, 108 name_short AS field_label 109 FROM ref.v_paperwork_templates 110 WHERE name_short %(fragment_condition)s 111 ORDER BY name_short 112 """ 113 gmMatchProvider.cMatchProvider_SQL2.__init__(self, queries = [query])116132 #============================================================118 119 query = u""" 120 SELECT DISTINCT ON (list_label) 121 pk AS data, 122 _(name) || ' (' || name || ')' AS list_label, 123 _(name) AS field_label 124 FROM ref.form_types 125 WHERE 126 _(name) %(fragment_condition)s 127 OR 128 name %(fragment_condition)s 129 ORDER BY list_label 130 """ 131 gmMatchProvider.cMatchProvider_SQL2.__init__(self, queries = [query])134 135 _cmd_fetch_payload = u'select * from ref.v_paperwork_templates where pk_paperwork_template = %s' 136 137 _cmds_store_payload = [ 138 u"""update ref.paperwork_templates set 139 name_short = %(name_short)s, 140 name_long = %(name_long)s, 141 fk_template_type = %(pk_template_type)s, 142 instance_type = %(instance_type)s, 143 engine = %(engine)s, 144 in_use = %(in_use)s, 145 filename = %(filename)s, 146 external_version = %(external_version)s 147 where 148 pk = %(pk_paperwork_template)s and 149 xmin = %(xmin_paperwork_template)s 150 """, 151 u"""select xmin_paperwork_template from ref.v_paperwork_templates where pk_paperwork_template = %(pk_paperwork_template)s""" 152 ] 153 154 _updatable_fields = [ 155 u'name_short', 156 u'name_long', 157 u'external_version', 158 u'pk_template_type', 159 u'instance_type', 160 u'engine', 161 u'in_use', 162 u'filename' 163 ] 164 165 _suffix4engine = { 166 u'O': u'.ott', 167 u'L': u'.tex', 168 u'T': u'.txt', 169 u'X': u'.xslt', 170 u'I': u'.img', 171 u'P': u'.pdf' 172 } 173 174 #--------------------------------------------------------242 #============================================================176 """The template itself better not be arbitrarily large unless you can handle that. 177 178 Note that the data type returned will be a buffer.""" 179 180 cmd = u'SELECT data FROM ref.paperwork_templates WHERE pk = %(pk)s' 181 rows, idx = gmPG2.run_ro_queries (queries = [{'cmd': cmd, 'args': {'pk': self.pk_obj}}], get_col_idx = False) 182 183 if len(rows) == 0: 184 raise gmExceptions.NoSuchBusinessObjectError('cannot retrieve data for template pk = %s' % self.pk_obj) 185 186 return rows[0][0]187 188 template_data = property(_get_template_data, lambda x:x) 189 #--------------------------------------------------------191 """Export form template from database into file.""" 192 193 if filename is None: 194 if self._payload[self._idx['filename']] is None: 195 suffix = self.__class__._suffix4engine[self._payload[self._idx['engine']]] 196 else: 197 suffix = os.path.splitext(self._payload[self._idx['filename']].strip())[1].strip() 198 if suffix in [u'', u'.']: 199 suffix = self.__class__._suffix4engine[self._payload[self._idx['engine']]] 200 201 filename = gmTools.get_unique_filename ( 202 prefix = 'gm-%s-Template-' % self._payload[self._idx['engine']], 203 suffix = suffix 204 ) 205 206 data_query = { 207 'cmd': u'SELECT substring(data from %(start)s for %(size)s) FROM ref.paperwork_templates WHERE pk = %(pk)s', 208 'args': {'pk': self.pk_obj} 209 } 210 211 data_size_query = { 212 'cmd': u'select octet_length(data) from ref.paperwork_templates where pk = %(pk)s', 213 'args': {'pk': self.pk_obj} 214 } 215 216 result = gmPG2.bytea2file ( 217 data_query = data_query, 218 filename = filename, 219 data_size_query = data_size_query, 220 chunk_size = chunksize 221 ) 222 if result is False: 223 return None 224 225 return filename226 #--------------------------------------------------------228 gmPG2.file2bytea ( 229 filename = filename, 230 query = u'update ref.paperwork_templates set data = %(data)s::bytea where pk = %(pk)s and xmin = %(xmin)s', 231 args = {'pk': self.pk_obj, 'xmin': self._payload[self._idx['xmin_paperwork_template']]} 232 ) 233 # adjust for xmin change 234 self.refetch_payload()235 #--------------------------------------------------------237 fname = self.export_to_file() 238 engine = form_engines[self._payload[self._idx['engine']]] 239 form = engine(template_file = fname) 240 form.template = self 241 return form244 cmd = u'select pk from ref.paperwork_templates where name_long = %(lname)s and external_version = %(ver)s' 245 args = {'lname': name_long, 'ver': external_version} 246 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': cmd, 'args': args}], get_col_idx = False) 247 248 if len(rows) == 0: 249 _log.error('cannot load form template [%s - %s]', name_long, external_version) 250 return None 251 252 return cFormTemplate(aPK_obj = rows[0]['pk'])253 #------------------------------------------------------------254 -def get_form_templates(engine=None, active_only=False, template_types=None, excluded_types=None):255 """Load form templates.""" 256 257 args = {'eng': engine, 'in_use': active_only} 258 where_parts = [u'1 = 1'] 259 260 if engine is not None: 261 where_parts.append(u'engine = %(eng)s') 262 263 if active_only: 264 where_parts.append(u'in_use IS true') 265 266 if template_types is not None: 267 args['incl_types'] = tuple(template_types) 268 where_parts.append(u'template_type IN %(incl_types)s') 269 270 if excluded_types is not None: 271 args['excl_types'] = tuple(excluded_types) 272 where_parts.append(u'template_type NOT IN %(excl_types)s') 273 274 cmd = u"SELECT * FROM ref.v_paperwork_templates WHERE %s ORDER BY in_use desc, name_long" % u'\nAND '.join(where_parts) 275 276 rows, idx = gmPG2.run_ro_queries ( 277 queries = [{'cmd': cmd, 'args': args}], 278 get_col_idx = True 279 ) 280 templates = [ cFormTemplate(row = {'pk_field': 'pk_paperwork_template', 'data': r, 'idx': idx}) for r in rows ] 281 282 return templates283 #------------------------------------------------------------285 286 cmd = u'insert into ref.paperwork_templates (fk_template_type, name_short, name_long, external_version) values (%(type)s, %(nshort)s, %(nlong)s, %(ext_version)s)' 287 rows, idx = gmPG2.run_rw_queries ( 288 queries = [ 289 {'cmd': cmd, 'args': {'type': template_type, 'nshort': name_short, 'nlong': name_long, 'ext_version': 'new'}}, 290 {'cmd': u"select currval(pg_get_serial_sequence('ref.paperwork_templates', 'pk'))"} 291 ], 292 return_data = True 293 ) 294 template = cFormTemplate(aPK_obj = rows[0][0]) 295 return template296 #------------------------------------------------------------298 rows, idx = gmPG2.run_rw_queries ( 299 queries = [ 300 {'cmd': u'delete from ref.paperwork_templates where pk=%(pk)s', 'args': {'pk': template['pk_paperwork_template']}} 301 ] 302 ) 303 return True304 #============================================================ 305 # OpenOffice/LibreOffice API 306 #============================================================ 307 uno = None 308 cOOoDocumentCloseListener = None 309 writer_binary = None 310 311 #-----------------------------------------------------------313 314 try: 315 which = subprocess.Popen ( 316 args = ('which', 'soffice'), 317 stdout = subprocess.PIPE, 318 stdin = subprocess.PIPE, 319 stderr = subprocess.PIPE, 320 universal_newlines = True 321 ) 322 except (OSError, ValueError, subprocess.CalledProcessError): 323 _log.exception('there was a problem executing [which soffice]') 324 return 325 326 soffice_path, err = which.communicate() 327 soffice_path = soffice_path.strip('\n') 328 uno_path = os.path.abspath ( os.path.join ( 329 os.path.dirname(os.path.realpath(soffice_path)), 330 '..', 331 'basis-link', 332 'program' 333 )) 334 335 _log.info('UNO should be at [%s], appending to sys.path', uno_path) 336 337 sys.path.append(uno_path)338 #-----------------------------------------------------------340 """FIXME: consider this: 341 342 try: 343 import uno 344 except: 345 print "This Script needs to be run with the python from OpenOffice.org" 346 print "Example: /opt/OpenOffice.org/program/python %s" % ( 347 os.path.basename(sys.argv[0])) 348 print "Or you need to insert the right path at the top, where uno.py is." 349 print "Default: %s" % default_path 350 """ 351 global uno 352 if uno is not None: 353 return 354 355 try: 356 import uno 357 except ImportError: 358 __configure_path_to_UNO() 359 import uno 360 361 global unohelper, oooXCloseListener, oooNoConnectException, oooPropertyValue 362 363 import unohelper 364 from com.sun.star.util import XCloseListener as oooXCloseListener 365 from com.sun.star.connection import NoConnectException as oooNoConnectException 366 from com.sun.star.beans import PropertyValue as oooPropertyValue 367 368 #---------------------------------- 369 class _cOOoDocumentCloseListener(unohelper.Base, oooXCloseListener): 370 """Listens for events sent by OOo during the document closing 371 sequence and notifies the GNUmed client GUI so it can 372 import the closed document into the database. 373 """ 374 def __init__(self, document=None): 375 self.document = document376 377 def queryClosing(self, evt, owner): 378 # owner is True/False whether I am the owner of the doc 379 pass 380 381 def notifyClosing(self, evt): 382 pass 383 384 def disposing(self, evt): 385 self.document.on_disposed_by_ooo() 386 self.document = None 387 #---------------------------------- 388 389 global cOOoDocumentCloseListener 390 cOOoDocumentCloseListener = _cOOoDocumentCloseListener 391 392 # search for writer binary 393 global writer_binary 394 found, binary = gmShellAPI.find_first_binary(binaries = [ 395 'lowriter', 396 'oowriter' 397 ]) 398 if found: 399 _log.debug('OOo/LO writer binary found: %s', binary) 400 writer_binary = binary 401 else: 402 _log.debug('OOo/LO writer binary NOT found') 403 raise ImportError('LibreOffice/OpenOffice (lowriter/oowriter) not found') 404 405 _log.debug('python UNO bridge successfully initialized') 406 407 #------------------------------------------------------------409 """This class handles the connection to OOo. 410 411 Its Singleton instance stays around once initialized. 412 """ 413 # FIXME: need to detect closure of OOo !533 #------------------------------------------------------------415 416 init_ooo() 417 418 self.__setup_connection_string() 419 420 self.resolver_uri = "com.sun.star.bridge.UnoUrlResolver" 421 self.desktop_uri = "com.sun.star.frame.Desktop" 422 423 self.max_connect_attempts = 5 424 425 self.local_context = uno.getComponentContext() 426 self.uri_resolver = self.local_context.ServiceManager.createInstanceWithContext(self.resolver_uri, self.local_context) 427 428 self.__desktop = None429 #-------------------------------------------------------- 430 # external API 431 #--------------------------------------------------------433 if self.__desktop is None: 434 _log.debug('no desktop, no cleanup') 435 return 436 437 try: 438 self.__desktop.terminate() 439 except: 440 _log.exception('cannot terminate OOo desktop')441 #--------------------------------------------------------443 """<filename> must be absolute""" 444 if self.desktop is None: 445 _log.error('cannot access OOo desktop') 446 return None 447 448 filename = os.path.expanduser(filename) 449 filename = os.path.abspath(filename) 450 document_uri = uno.systemPathToFileUrl(filename) 451 452 _log.debug('%s -> %s', filename, document_uri) 453 454 doc = self.desktop.loadComponentFromURL(document_uri, "_blank", 0, ()) 455 return doc456 #-------------------------------------------------------- 457 # internal helpers 458 #--------------------------------------------------------460 # later factor this out ! 461 dbcfg = gmCfg.cCfgSQL() 462 self.ooo_startup_settle_time = dbcfg.get2 ( 463 option = u'external.ooo.startup_settle_time', 464 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 465 bias = u'workplace', 466 default = 3.0 467 )468 #--------------------------------------------------------470 471 # socket: 472 # ooo_port = u'2002' 473 # #self.ooo_start_cmd = 'oowriter -invisible -norestore -nofirststartwizard -nologo -accept="socket,host=localhost,port=%s;urp;StarOffice.ServiceManager"' % ooo_port 474 # self.ooo_start_cmd = 'oowriter -invisible -norestore -accept="socket,host=localhost,port=%s;urp;"' % ooo_port 475 # self.remote_context_uri = "uno:socket,host=localhost,port=%s;urp;StarOffice.ComponentContext" % ooo_port 476 477 # pipe: 478 pipe_name = "uno-gm2lo-%s" % str(random.random())[2:] 479 _log.debug('expecting OOo/LO server on named pipe [%s]', pipe_name) 480 self.ooo_start_cmd = '%s --invisible --norestore --accept="pipe,name=%s;urp" &' % ( 481 writer_binary, 482 pipe_name 483 ) 484 _log.debug('startup command: %s', self.ooo_start_cmd) 485 486 self.remote_context_uri = "uno:pipe,name=%s;urp;StarOffice.ComponentContext" % pipe_name 487 _log.debug('remote context URI: %s', self.remote_context_uri)488 #--------------------------------------------------------490 _log.info('trying to start OOo server') 491 _log.debug('startup command: %s', self.ooo_start_cmd) 492 os.system(self.ooo_start_cmd) 493 self.__get_startup_settle_time() 494 _log.debug('waiting %s seconds for OOo to start up', self.ooo_startup_settle_time) 495 time.sleep(self.ooo_startup_settle_time)496 #-------------------------------------------------------- 497 # properties 498 #--------------------------------------------------------500 if self.__desktop is not None: 501 return self.__desktop 502 503 self.remote_context = None 504 505 attempts = self.max_connect_attempts 506 while attempts > 0: 507 508 _log.debug(u'attempt %s/%s', self.max_connect_attempts - attempts + 1, self.max_connect_attempts) 509 510 try: 511 self.remote_context = self.uri_resolver.resolve(self.remote_context_uri) 512 break 513 except oooNoConnectException: 514 _log.exception('cannot connect to OOo') 515 516 # first loop ? 517 if attempts == self.max_connect_attempts: 518 self.__startup_ooo() 519 else: 520 time.sleep(1) 521 522 attempts = attempts - 1 523 524 if self.remote_context is None: 525 raise OSError(-1, u'cannot connect to OpenOffice', self.remote_context_uri) 526 527 _log.debug('connection seems established') 528 self.__desktop = self.remote_context.ServiceManager.createInstanceWithContext(self.desktop_uri, self.remote_context) 529 _log.debug('got OOo desktop handle') 530 return self.__desktop531 532 desktop = property(_get_desktop, lambda x:x)535640 #-------------------------------------------------------- 641 # internal helpers 642 #-------------------------------------------------------- 643 644 #============================================================537 538 self.template_file = template_file 539 self.instance_type = instance_type 540 self.ooo_doc = None541 #-------------------------------------------------------- 542 # external API 543 #--------------------------------------------------------545 # connect to OOo 546 ooo_srv = gmOOoConnector() 547 548 # open doc in OOo 549 self.ooo_doc = ooo_srv.open_document(filename = self.template_file) 550 if self.ooo_doc is None: 551 _log.error('cannot open document in OOo') 552 return False 553 554 # listen for close events 555 pat = gmPerson.gmCurrentPatient() 556 pat.locked = True 557 listener = cOOoDocumentCloseListener(document = self) 558 self.ooo_doc.addCloseListener(listener) 559 560 return True561 #-------------------------------------------------------- 564 #--------------------------------------------------------566 567 # new style embedded, implicit placeholders 568 searcher = self.ooo_doc.createSearchDescriptor() 569 searcher.SearchCaseSensitive = False 570 searcher.SearchRegularExpression = True 571 searcher.SearchWords = True 572 searcher.SearchString = handler.placeholder_regex 573 574 placeholder_instance = self.ooo_doc.findFirst(searcher) 575 while placeholder_instance is not None: 576 try: 577 val = handler[placeholder_instance.String] 578 except: 579 val = _('error with placeholder [%s]') % placeholder_instance.String 580 _log.exception(val) 581 582 if val is None: 583 val = _('error with placeholder [%s]') % placeholder_instance.String 584 585 placeholder_instance.String = val 586 placeholder_instance = self.ooo_doc.findNext(placeholder_instance.End, searcher) 587 588 if not old_style_too: 589 return 590 591 # old style "explicit" placeholders 592 text_fields = self.ooo_doc.getTextFields().createEnumeration() 593 while text_fields.hasMoreElements(): 594 text_field = text_fields.nextElement() 595 596 # placeholder ? 597 if not text_field.supportsService('com.sun.star.text.TextField.JumpEdit'): 598 continue 599 # placeholder of type text ? 600 if text_field.PlaceHolderType != 0: 601 continue 602 603 replacement = handler[text_field.PlaceHolder] 604 if replacement is None: 605 continue 606 607 text_field.Anchor.setString(replacement)608 #--------------------------------------------------------610 if filename is not None: 611 target_url = uno.systemPathToFileUrl(os.path.abspath(os.path.expanduser(filename))) 612 save_args = ( 613 oooPropertyValue('Overwrite', 0, True, 0), 614 oooPropertyValue('FormatFilter', 0, 'swriter: StarOffice XML (Writer)', 0) 615 616 ) 617 # "store AS url" stores the doc, marks it unmodified and updates 618 # the internal media descriptor - as opposed to "store TO url" 619 self.ooo_doc.storeAsURL(target_url, save_args) 620 else: 621 self.ooo_doc.store()622 #--------------------------------------------------------624 self.ooo_doc.dispose() 625 pat = gmPerson.gmCurrentPatient() 626 pat.locked = False 627 self.ooo_doc = None628 #--------------------------------------------------------630 # get current file name from OOo, user may have used Save As 631 filename = uno.fileUrlToSystemPath(self.ooo_doc.URL) 632 # tell UI to import the file 633 gmDispatcher.send ( 634 signal = u'import_document_from_file', 635 filename = filename, 636 document_type = self.instance_type, 637 unlock_patient = True 638 ) 639 self.ooo_doc = None646 """Ancestor for forms.""" 647664 #-------------------------------------------------------- 665 #-------------------------------------------------------- 666 # def process(self, data_source=None): 667 # """Merge values into the form template. 668 # """ 669 # pass 670 # #-------------------------------------------------------- 671 # def cleanup(self): 672 # """ 673 # A sop to TeX which can't act as a true filter: to delete temporary files 674 # """ 675 # pass 676 # #-------------------------------------------------------- 677 # def exe(self, command): 678 # """ 679 # Executes the provided command. 680 # If command cotains %F. it is substituted with the filename 681 # Otherwise, the file is fed in on stdin 682 # """ 683 # pass 684 # #-------------------------------------------------------- 685 # def store(self, params=None): 686 # """Stores the parameters in the backend. 687 # 688 # - link_obj can be a cursor, a connection or a service name 689 # - assigning a cursor to link_obj allows the calling code to 690 # group the call to store() into an enclosing transaction 691 # (for an example see gmReferral.send_referral()...) 692 # """ 693 # # some forms may not have values ... 694 # if params is None: 695 # params = {} 696 # patient_clinical = self.patient.get_emr() 697 # encounter = patient_clinical.active_encounter['pk_encounter'] 698 # # FIXME: get_active_episode is no more 699 # #episode = patient_clinical.get_active_episode()['pk_episode'] 700 # # generate "forever unique" name 701 # cmd = "select name_short || ': <' || name_long || '::' || external_version || '>' from paperwork_templates where pk=%s"; 702 # rows = gmPG.run_ro_query('reference', cmd, None, self.pk_def) 703 # form_name = None 704 # if rows is None: 705 # _log.error('error retrieving form def for [%s]' % self.pk_def) 706 # elif len(rows) == 0: 707 # _log.error('no form def for [%s]' % self.pk_def) 708 # else: 709 # form_name = rows[0][0] 710 # # we didn't get a name but want to store the form anyhow 711 # if form_name is None: 712 # form_name=time.time() # hopefully unique enough 713 # # in one transaction 714 # queries = [] 715 # # - store form instance in form_instance 716 # cmd = "insert into form_instances(fk_form_def, form_name, fk_episode, fk_encounter) values (%s, %s, %s, %s)" 717 # queries.append((cmd, [self.pk_def, form_name, episode, encounter])) 718 # # - store params in form_data 719 # for key in params.keys(): 720 # cmd = """ 721 # insert into form_data(fk_instance, place_holder, value) 722 # values ((select currval('form_instances_pk_seq')), %s, %s::text) 723 # """ 724 # queries.append((cmd, [key, params[key]])) 725 # # - get inserted PK 726 # queries.append(("select currval ('form_instances_pk_seq')", [])) 727 # status, err = gmPG.run_commit('historica', queries, True) 728 # if status is None: 729 # _log.error('failed to store form [%s] (%s): %s' % (self.pk_def, form_name, err)) 730 # return None 731 # return status 732 733 #================================================================ 734 # OOo template forms 735 #----------------------------------------------------------------649 self.template = None 650 self.template_filename = template_file 651 _log.debug('working on template file [%s]', self.template_filename)652 #--------------------------------------------------------654 """Parse the template into an instance and replace placeholders with values.""" 655 raise NotImplementedError656 #-------------------------------------------------------- 660 #--------------------------------------------------------737 """A forms engine wrapping OOo.""" 738746 747 #================================================================ 748 # AbiWord template forms 749 #----------------------------------------------------------------740 super(self.__class__, self).__init__(template_file = template_file) 741 742 path, ext = os.path.splitext(self.template_filename) 743 if ext in [r'', r'.']: 744 ext = r'.odt' 745 self.instance_filename = r'%s-instance%s' % (path, ext)751 """A forms engine wrapping AbiWord.""" 752 753 placeholder_regex = r'\$<.+?>\$' 754828 #---------------------------------------------------------------- 829 form_engines[u'A'] = cAbiWordForm 830 831 #================================================================ 832 # text template forms 833 #----------------------------------------------------------------756 757 super(cAbiWordForm, self).__init__(template_file = template_file) 758 759 # detect abiword 760 found, self.abiword_binary = gmShellAPI.detect_external_binary(binary = r'abiword') 761 if not found: 762 raise ImportError('<abiword(.exe)> not found')763 #--------------------------------------------------------765 # should *actually* properly parse the XML 766 767 path, ext = os.path.splitext(self.template_filename) 768 if ext in [r'', r'.']: 769 ext = r'.abw' 770 self.instance_filename = r'%s-instance%s' % (path, ext) 771 772 template_file = codecs.open(self.template_filename, 'rU', 'utf8') 773 instance_file = codecs.open(self.instance_filename, 'wb', 'utf8') 774 775 if self.template is not None: 776 # inject placeholder values 777 data_source.set_placeholder(u'form_name_long', self.template['name_long']) 778 data_source.set_placeholder(u'form_name_short', self.template['name_short']) 779 data_source.set_placeholder(u'form_version', self.template['external_version']) 780 781 data_source.escape_style = u'xml' 782 data_source.escape_function = None # gmTools.xml_escape_text() ? 783 784 for line in template_file: 785 786 if line.strip() in [u'', u'\r', u'\n', u'\r\n']: 787 instance_file.write(line) 788 continue 789 790 # 1) find placeholders in this line 791 placeholders_in_line = regex.findall(cAbiWordForm.placeholder_regex, line, regex.IGNORECASE) 792 # 2) and replace them 793 for placeholder in placeholders_in_line: 794 try: 795 val = data_source[placeholder.replace(u'<', u'<').replace(u'>', u'>')] 796 except: 797 val = _('error with placeholder [%s]') % gmTools.xml_escape_string(placeholder) 798 _log.exception(val) 799 800 if val is None: 801 val = _('error with placeholder [%s]') % gmTools.xml_escape_string(placeholder) 802 803 line = line.replace(placeholder, val) 804 805 instance_file.write(line) 806 807 instance_file.close() 808 template_file.close() 809 810 if self.template is not None: 811 # remove temporary placeholders 812 data_source.unset_placeholder(u'form_name_long') 813 data_source.unset_placeholder(u'form_name_short') 814 data_source.unset_placeholder(u'form_version') 815 816 return817 #--------------------------------------------------------819 enc = sys.getfilesystemencoding() 820 cmd = (r'%s %s' % (self.abiword_binary, self.instance_filename.encode(enc))).encode(enc) 821 result = gmShellAPI.run_command_in_shell(command = cmd, blocking = True) 822 self.re_editable_filenames = [] 823 return result824 #--------------------------------------------------------835 """A forms engine outputting data as text for further processing.""" 836930 #------------------------------------------------------------ 931 form_engines[u'T'] = cTextForm 932 933 #================================================================ 934 # LaTeX template forms 935 #----------------------------------------------------------------838 super(self.__class__, self).__init__(template_file = template_file) 839 840 # generate real template file from .ini file 841 cfg_file = codecs.open(filename = self.template_filename, mode = 'rU', encoding = u'utf8') 842 self.form_definition = gmCfg2.parse_INI_stream(stream = cfg_file) 843 cfg_file.close() 844 self.form_definition['form::template']845 #--------------------------------------------------------847 self.instance_filename = gmTools.get_unique_filename ( 848 prefix = 'gm-T-instance-', 849 suffix = '.txt' 850 ) 851 instance_file = codecs.open(self.instance_filename, 'wb', 'utf8') 852 853 if self.template is not None: 854 # inject placeholder values 855 data_source.set_placeholder(u'form_name_long', self.template['name_long']) 856 data_source.set_placeholder(u'form_name_short', self.template['name_short']) 857 data_source.set_placeholder(u'form_version', self.template['external_version']) 858 859 if isinstance(self.form_definition['form::template'], type([])): 860 template_text = self.form_definition['form::template'] 861 else: 862 template_text = self.form_definition['form::template'].split('\n') 863 864 no_errors = True 865 for line in template_text: 866 if line.strip() in [u'', u'\r', u'\n', u'\r\n']: 867 instance_file.write('%s\n' % line) 868 continue 869 870 # 1) find placeholders in this line 871 placeholders_in_line = regex.findall(data_source.placeholder_regex, line, regex.IGNORECASE) 872 # 2) and replace them 873 for placeholder in placeholders_in_line: 874 try: 875 val = data_source[placeholder] 876 except: 877 val = _('error with placeholder [%s]') % placeholder 878 _log.exception(val) 879 no_errors = False 880 881 if val is None: 882 val = _('error with placeholder [%s]') % placeholder 883 884 line = line.replace(placeholder, val) 885 886 instance_file.write(u'%s\n' % line) 887 888 instance_file.close() 889 self.re_editable_filenames = [self.instance_filename] 890 891 if self.template is not None: 892 # remove temporary placeholders 893 data_source.unset_placeholder(u'form_name_long') 894 data_source.unset_placeholder(u'form_name_short') 895 data_source.unset_placeholder(u'form_version') 896 897 return no_errors898 #--------------------------------------------------------900 901 editor_cmd = None 902 try: 903 editor_cmd = self.form_definition['form::editor'] % self.instance_filename 904 except KeyError: 905 _log.debug('no explicit editor defined for text template') 906 907 if editor_cmd is None: 908 mimetype = u'text/plain' 909 editor_cmd = gmMimeLib.get_editor_cmd(mimetype, self.instance_filename) 910 if editor_cmd is None: 911 # also consider text *viewers* since pretty much any of them will be an editor as well 912 editor_cmd = gmMimeLib.get_viewer_cmd(mimetype, self.instance_filename) 913 914 if editor_cmd is not None: 915 result = gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = True) 916 self.re_editable_filenames = [self.instance_filename] 917 918 return result919 #--------------------------------------------------------921 try: 922 post_processor = self.form_definition['form::post processor'] % self.instance_filename 923 except KeyError: 924 _log.debug('no explicit post processor defined for text template') 925 return True 926 927 self.final_output_filenames = [self.instance_filename] 928 929 return gmShellAPI.run_command_in_shell(command = post_processor, blocking = True)937 """A forms engine wrapping LaTeX.""" 9381121 #------------------------------------------------------------ 1122 form_engines[u'L'] = cLaTeXForm 1123 1124 #================================================================ 1125 # Xe(La)TeX template forms 1126 #---------------------------------------------------------------- 1127 # Xe(La)TeX: http://www.scholarsfonts.net/xetextt.pdf940 941 # create sandbox for LaTeX to play in (and don't assume 942 # much of anything about the template_file except that it 943 # is at our disposal) 944 sandbox_dir = gmTools.get_unique_filename ( 945 prefix = gmTools.fname_stem(template_file) + '_', 946 suffix = '.dir' 947 ) 948 _log.debug('LaTeX sandbox directory: [%s]', sandbox_dir) 949 gmTools.mkdir(sandbox_dir) 950 shutil.copy(template_file, sandbox_dir) 951 template_file = os.path.join(sandbox_dir, os.path.split(template_file)[1]) 952 953 super(self.__class__, self).__init__(template_file = template_file) 954 955 self.__sandbox_dir = sandbox_dir956 #--------------------------------------------------------958 959 if self.template is not None: 960 # inject placeholder values 961 data_source.set_placeholder(u'form_name_long', self.template['name_long']) 962 data_source.set_placeholder(u'form_name_short', self.template['name_short']) 963 data_source.set_placeholder(u'form_version', self.template['external_version']) 964 965 data_source.escape_function = gmTools.tex_escape_string 966 data_source.escape_style = u'latex' 967 968 path, ext = os.path.splitext(self.template_filename) 969 if ext in [r'', r'.']: 970 ext = r'.tex' 971 972 filenames = [ 973 self.template_filename, 974 r'%s-result_run1%s' % (path, ext), 975 r'%s-result_run2%s' % (path, ext), 976 r'%s-result_run3%s' % (path, ext) 977 ] 978 979 found_placeholders = True 980 current_run = 1 981 while found_placeholders and (current_run < 4): 982 _log.debug('placeholder substitution run #%s', current_run) 983 found_placeholders = self.__substitute_placeholders ( 984 input_filename = filenames[current_run-1], 985 output_filename = filenames[current_run], 986 data_source = data_source 987 ) 988 current_run += 1 989 990 if self.template is not None: 991 # remove temporary placeholders 992 data_source.unset_placeholder(u'form_name_long') 993 data_source.unset_placeholder(u'form_name_short') 994 data_source.unset_placeholder(u'form_version') 995 996 self.instance_filename = self.re_editable_filenames[0] 997 998 return999 #--------------------------------------------------------1000 - def __substitute_placeholders(self, data_source=None, input_filename=None, output_filename=None):1001 1002 _log.debug('[%s] -> [%s]', input_filename, output_filename) 1003 1004 found_placeholders = False 1005 1006 template_file = codecs.open(input_filename, 'rU', 'utf8') 1007 instance_file = codecs.open(output_filename, 'wb', 'utf8') 1008 1009 for line in template_file: 1010 1011 if line.strip() in [u'', u'\r', u'\n', u'\r\n']: # empty lines 1012 instance_file.write(line) 1013 continue 1014 if line.lstrip().startswith('%'): # TeX comment 1015 instance_file.write(line) 1016 continue 1017 1018 for placeholder_regex in [data_source.first_order_placeholder_regex, data_source.second_order_placeholder_regex, data_source.third_order_placeholder_regex]: 1019 # 1) find placeholders in this line 1020 placeholders_in_line = regex.findall(placeholder_regex, line, regex.IGNORECASE) 1021 if len(placeholders_in_line) == 0: 1022 continue 1023 _log.debug('%s placeholders found with pattern: %s', len(placeholders_in_line), placeholder_regex) 1024 found_placeholders = True 1025 # 2) replace them 1026 for placeholder in placeholders_in_line: 1027 try: 1028 val = data_source[placeholder] 1029 except: 1030 _log.exception('error with placeholder [%s]', placeholder) 1031 val = gmTools.tex_escape_string(_('error with placeholder [%s]') % placeholder) 1032 1033 if val is None: 1034 _log.debug('error with placeholder [%s]', placeholder) 1035 val = _('error with placeholder [%s]') % gmTools.tex_escape_string(placeholder) 1036 1037 line = line.replace(placeholder, val) 1038 1039 instance_file.write(line) 1040 1041 instance_file.close() 1042 self.re_editable_filenames = [output_filename] 1043 template_file.close() 1044 1045 return found_placeholders1046 #--------------------------------------------------------1048 1049 mimetypes = [ 1050 u'application/x-latex', 1051 u'application/x-tex', 1052 u'text/plain' 1053 ] 1054 1055 for mimetype in mimetypes: 1056 editor_cmd = gmMimeLib.get_editor_cmd(mimetype, self.instance_filename) 1057 if editor_cmd is not None: 1058 break 1059 1060 if editor_cmd is None: 1061 # LaTeX code is text: also consider text *viewers* 1062 # since pretty much any of them will be an editor as well 1063 for mimetype in mimetypes: 1064 editor_cmd = gmMimeLib.get_viewer_cmd(mimetype, self.instance_filename) 1065 if editor_cmd is not None: 1066 break 1067 1068 if editor_cmd is None: 1069 return False 1070 1071 result = gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = True) 1072 self.re_editable_filenames = [self.instance_filename] 1073 return result1074 #--------------------------------------------------------1076 1077 if instance_file is None: 1078 instance_file = self.instance_filename 1079 1080 try: 1081 open(instance_file, 'r').close() 1082 except: 1083 _log.exception('cannot access form instance file [%s]', instance_file) 1084 gmLog2.log_stack_trace() 1085 return None 1086 1087 self.instance_filename = instance_file 1088 1089 _log.debug('ignoring <format> directive [%s], generating PDF', format) 1090 1091 # LaTeX can need up to three runs to get cross references et al right 1092 if platform.system() == 'Windows': 1093 draft_cmd = r'pdflatex.exe -draftmode -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1094 final_cmd = r'pdflatex.exe -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1095 else: 1096 draft_cmd = r'pdflatex -draftmode -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1097 final_cmd = r'pdflatex -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1098 for run_cmd in [draft_cmd, draft_cmd, final_cmd]: 1099 if not gmShellAPI.run_command_in_shell(command = run_cmd, blocking = True, acceptable_return_codes = [0, 1]): 1100 _log.error('problem running pdflatex, cannot generate form output') 1101 gmDispatcher.send(signal = 'statustext', msg = _('Error running pdflatex. Cannot turn LaTeX template into PDF.'), beep = True) 1102 return None 1103 1104 sandboxed_pdf_name = u'%s.pdf' % os.path.splitext(self.instance_filename)[0] 1105 target_dir = os.path.normpath(os.path.join(os.path.split(sandboxed_pdf_name)[0], '..')) 1106 final_pdf_name = os.path.join ( 1107 target_dir, 1108 os.path.split(sandboxed_pdf_name)[1] 1109 ) 1110 _log.debug('copying sandboxed PDF: %s -> %s', sandboxed_pdf_name, final_pdf_name) 1111 try: 1112 shutil.copy2(sandboxed_pdf_name, target_dir) 1113 except IOError: 1114 _log.exception('cannot open/move sandboxed PDF') 1115 gmDispatcher.send(signal = 'statustext', msg = _('PDF output file cannot be opened.'), beep = True) 1116 return None 1117 1118 self.final_output_filenames = [final_pdf_name] 1119 1120 return final_pdf_name1129 """A forms engine wrapping Xe(La)TeX.""" 11301317 1318 #------------------------------------------------------------ 1319 form_engines[u'X'] = cXeTeXForm 1320 1321 #============================================================ 1322 # Gnuplot template forms 1323 #------------------------------------------------------------1132 1133 # create sandbox for LaTeX to play in (and don't assume 1134 # much of anything about the template_file except that it 1135 # is at our disposal) 1136 sandbox_dir = gmTools.get_unique_filename ( 1137 prefix = gmTools.fname_stem(template_file) + '_', 1138 suffix = '.dir' 1139 ) 1140 _log.debug('Xe(La)TeX sandbox directory: [%s]', sandbox_dir) 1141 gmTools.mkdir(sandbox_dir) 1142 shutil.copy(template_file, sandbox_dir) 1143 template_file = os.path.join(sandbox_dir, os.path.split(template_file)[1]) 1144 1145 super(self.__class__, self).__init__(template_file = template_file) 1146 1147 self.__sandbox_dir = sandbox_dir1148 #--------------------------------------------------------1150 1151 if self.template is not None: 1152 # inject placeholder values 1153 data_source.set_placeholder(u'form_name_long', self.template['name_long']) 1154 data_source.set_placeholder(u'form_name_short', self.template['name_short']) 1155 data_source.set_placeholder(u'form_version', self.template['external_version']) 1156 1157 data_source.escape_function = gmTools.xetex_escape_string 1158 data_source.escape_style = u'xetex' 1159 1160 path, ext = os.path.splitext(self.template_filename) 1161 if ext in [r'', r'.']: 1162 ext = r'.tex' 1163 1164 filenames = [ 1165 self.template_filename, 1166 r'%s-result_run1%s' % (path, ext), 1167 r'%s-result_run2%s' % (path, ext), 1168 r'%s-result_run3%s' % (path, ext) 1169 ] 1170 1171 found_placeholders = True 1172 current_run = 1 1173 while found_placeholders and (current_run < 4): 1174 _log.debug('placeholder substitution run #%s', current_run) 1175 found_placeholders = self.__substitute_placeholders ( 1176 input_filename = filenames[current_run-1], 1177 output_filename = filenames[current_run], 1178 data_source = data_source 1179 ) 1180 current_run += 1 1181 1182 if self.template is not None: 1183 # remove temporary placeholders 1184 data_source.unset_placeholder(u'form_name_long') 1185 data_source.unset_placeholder(u'form_name_short') 1186 data_source.unset_placeholder(u'form_version') 1187 1188 self.instance_filename = self.re_editable_filenames[0] 1189 1190 return1191 #--------------------------------------------------------1192 - def __substitute_placeholders(self, data_source=None, input_filename=None, output_filename=None):1193 _log.debug('[%s] -> [%s]', input_filename, output_filename) 1194 1195 found_placeholders = False 1196 1197 template_file = codecs.open(input_filename, 'rU', 'utf8') 1198 instance_file = codecs.open(output_filename, 'wb', 'utf8') 1199 1200 for line in template_file: 1201 1202 if line.strip() in [u'', u'\r', u'\n', u'\r\n']: # empty lines 1203 instance_file.write(line) 1204 continue 1205 if line.startswith('%'): # TeX comment 1206 instance_file.write(line) 1207 continue 1208 1209 for placeholder_regex in [data_source.first_order_placeholder_regex, data_source.second_order_placeholder_regex, data_source.third_order_placeholder_regex]: 1210 # 1) find placeholders in this line 1211 placeholders_in_line = regex.findall(placeholder_regex, line, regex.IGNORECASE) 1212 if len(placeholders_in_line) == 0: 1213 continue 1214 _log.debug('%s placeholders found with pattern: %s', len(placeholders_in_line), placeholder_regex) 1215 found_placeholders = True 1216 # 2) replace them 1217 for placeholder in placeholders_in_line: 1218 try: 1219 val = data_source[placeholder] 1220 except: 1221 _log.exception('error with placeholder [%s]', placeholder) 1222 val = gmTools.tex_escape_string(_('error with placeholder [%s]') % placeholder) 1223 1224 if val is None: 1225 _log.debug('error with placeholder [%s]', placeholder) 1226 val = _('error with placeholder [%s]') % gmTools.tex_escape_string(placeholder) 1227 1228 line = line.replace(placeholder, val) 1229 1230 instance_file.write(line) 1231 1232 instance_file.close() 1233 self.re_editable_filenames = [output_filename] 1234 template_file.close() 1235 1236 return found_placeholders1237 #--------------------------------------------------------1239 1240 mimetypes = [ 1241 u'application/x-xetex', 1242 u'application/x-latex', 1243 u'application/x-tex', 1244 u'text/plain' 1245 ] 1246 1247 for mimetype in mimetypes: 1248 editor_cmd = gmMimeLib.get_editor_cmd(mimetype, self.instance_filename) 1249 if editor_cmd is not None: 1250 break 1251 1252 if editor_cmd is None: 1253 # Xe(La)TeX code is utf8: also consider text *viewers* 1254 # since pretty much any of them will be an editor as well 1255 for mimetype in mimetypes: 1256 editor_cmd = gmMimeLib.get_viewer_cmd(mimetype, self.instance_filename) 1257 if editor_cmd is not None: 1258 break 1259 1260 if editor_cmd is None: 1261 return False 1262 1263 result = gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = True) 1264 self.re_editable_filenames = [self.instance_filename] 1265 return result1266 #--------------------------------------------------------1268 1269 if instance_file is None: 1270 instance_file = self.instance_filename 1271 1272 try: 1273 open(instance_file, 'r').close() 1274 except: 1275 _log.exception('cannot access form instance file [%s]', instance_file) 1276 gmLog2.log_stack_trace() 1277 return None 1278 1279 self.instance_filename = instance_file 1280 1281 _log.debug('ignoring <format> directive [%s], generating PDF', format) 1282 1283 # Xe(La)TeX can need up to three runs to get cross references et al right 1284 if platform.system() == 'Windows': 1285 # not yet supported: -draftmode 1286 # does not support: -shell-escape 1287 draft_cmd = r'xelatex.exe -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1288 final_cmd = r'xelatex.exe -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1289 else: 1290 # not yet supported: -draftmode 1291 draft_cmd = r'xelatex -interaction=nonstopmode -output-directory=%s -shell-escape %s' % (self.__sandbox_dir, self.instance_filename) 1292 final_cmd = r'xelatex -interaction=nonstopmode -output-directory=%s -shell-escape %s' % (self.__sandbox_dir, self.instance_filename) 1293 1294 for run_cmd in [draft_cmd, draft_cmd, final_cmd]: 1295 if not gmShellAPI.run_command_in_shell(command = run_cmd, blocking = True, acceptable_return_codes = [0, 1]): 1296 _log.error('problem running xelatex, cannot generate form output') 1297 gmDispatcher.send(signal = 'statustext', msg = _('Error running xelatex. Cannot turn Xe(La)TeX template into PDF.'), beep = True) 1298 return None 1299 1300 sandboxed_pdf_name = u'%s.pdf' % os.path.splitext(self.instance_filename)[0] 1301 target_dir = os.path.normpath(os.path.join(os.path.split(sandboxed_pdf_name)[0], '..')) 1302 final_pdf_name = os.path.join ( 1303 target_dir, 1304 os.path.split(sandboxed_pdf_name)[1] 1305 ) 1306 _log.debug('copying sandboxed PDF: %s -> %s', sandboxed_pdf_name, final_pdf_name) 1307 try: 1308 shutil.copy2(sandboxed_pdf_name, target_dir) 1309 except IOError: 1310 _log.exception('cannot open/move sandboxed PDF') 1311 gmDispatcher.send(signal = 'statustext', msg = _('PDF output file cannot be opened.'), beep = True) 1312 return None 1313 1314 self.final_output_filenames = [final_pdf_name] 1315 1316 return final_pdf_name1325 """A forms engine wrapping Gnuplot.""" 1326 1327 #-------------------------------------------------------- 1331 #--------------------------------------------------------1376 #------------------------------------------------------------ 1377 form_engines[u'G'] = cGnuplotForm 1378 1379 #============================================================ 1380 # fPDF form engine 1381 #------------------------------------------------------------1333 """Allow editing the instance of the template.""" 1334 self.re_editable_filenames = [] 1335 return True1336 #--------------------------------------------------------1338 """Generate output suitable for further processing outside this class, e.g. printing. 1339 1340 Expects .data_filename to be set. 1341 """ 1342 self.conf_filename = gmTools.get_unique_filename(prefix = 'gm2gpl-', suffix = '.conf') 1343 conf_file = codecs.open(self.conf_filename, 'wb', 'utf8') 1344 conf_file.write('# setting the gnuplot data file\n') 1345 conf_file.write("gm2gpl_datafile = '%s'\n" % self.data_filename) 1346 conf_file.close() 1347 1348 # FIXME: cater for configurable path 1349 if platform.system() == 'Windows': 1350 exec_name = 'gnuplot.exe' 1351 else: 1352 exec_name = 'gnuplot' 1353 1354 args = [exec_name, '-p', self.conf_filename, self.template_filename] 1355 _log.debug('plotting args: %s' % str(args)) 1356 1357 try: 1358 gp = subprocess.Popen ( 1359 args = args, 1360 close_fds = True 1361 ) 1362 except (OSError, ValueError, subprocess.CalledProcessError): 1363 _log.exception('there was a problem executing gnuplot') 1364 gmDispatcher.send(signal = u'statustext', msg = _('Error running gnuplot. Cannot plot data.'), beep = True) 1365 return 1366 1367 gp.communicate() 1368 1369 self.final_output_filenames = [ 1370 self.conf_filename, 1371 self.data_filename, 1372 self.template_filename 1373 ] 1374 1375 return1383 """A forms engine wrapping PDF forms. 1384 1385 Johann Felix Soden <johfel@gmx.de> helped with this. 1386 1387 http://partners.adobe.com/public/developer/en/pdf/PDFReference16.pdf 1388 1389 http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/fdf_data_exchange.pdf 1390 """ 13911588 #------------------------------------------------------------ 1589 form_engines[u'P'] = cPDFForm 1590 1591 #============================================================ 1592 # older code 1593 #------------------------------------------------------------1393 1394 super(cPDFForm, self).__init__(template_file = template_file) 1395 1396 # detect pdftk 1397 found, self.pdftk_binary = gmShellAPI.detect_external_binary(binary = r'pdftk') 1398 if not found: 1399 raise ImportError('<pdftk(.exe)> not found') 1400 return # should be superfluous, actually 1401 1402 enc = sys.getfilesystemencoding() 1403 self.pdftk_binary = self.pdftk_binary.encode(enc) 1404 1405 base_name, ext = os.path.splitext(self.template_filename) 1406 self.fdf_dumped_filename = (u'%s.fdf' % base_name).encode(enc) 1407 self.fdf_replaced_filename = (u'%s-replaced.fdf' % base_name).encode(enc) 1408 self.pdf_filled_filename = (u'%s-filled.pdf' % base_name).encode(enc) 1409 self.pdf_flattened_filename = (u'%s-filled-flattened.pdf' % base_name).encode(enc)1410 #--------------------------------------------------------1412 1413 # dump form fields from template 1414 cmd_line = [ 1415 self.pdftk_binary, 1416 self.template_filename, 1417 r'generate_fdf', 1418 r'output', 1419 self.fdf_dumped_filename 1420 ] 1421 _log.debug(u' '.join(cmd_line)) 1422 try: 1423 pdftk = subprocess.Popen(cmd_line) 1424 except OSError: 1425 _log.exception('cannot run <pdftk> (dump data from form)') 1426 gmDispatcher.send(signal = u'statustext', msg = _('Error running pdftk. Cannot extract fields from PDF form template.'), beep = True) 1427 return False 1428 1429 pdftk.communicate() 1430 if pdftk.returncode != 0: 1431 _log.error('<pdftk> returned [%s], failed to dump data from PDF form into FDF', pdftk.returncode) 1432 return False 1433 1434 # parse dumped FDF file for "/V (...)" records 1435 # and replace placeholders therein 1436 fdf_dumped_file = open(self.fdf_dumped_filename, 'rbU') 1437 fdf_replaced_file = codecs.open(self.fdf_replaced_filename, 'wb') 1438 1439 string_value_regex = r'\s*/V\s*\(.+\)\s*$' 1440 for line in fdf_dumped_file: 1441 if not regex.match(string_value_regex, line): 1442 fdf_replaced_file.write(line) 1443 continue 1444 1445 # strip cruft around the string value 1446 raw_str_val = line.strip() # remove framing whitespace 1447 raw_str_val = raw_str_val[2:] # remove leading "/V" 1448 raw_str_val = raw_str_val.lstrip() # remove whitespace between "/V" and "(" 1449 raw_str_val = raw_str_val[1:] # remove opening "(" 1450 raw_str_val = raw_str_val[2:] # remove BOM-16-BE 1451 raw_str_val = raw_str_val.rstrip() # remove trailing whitespace 1452 raw_str_val = raw_str_val[:-1] # remove closing ")" 1453 1454 # work on FDF escapes 1455 raw_str_val = raw_str_val.replace('\(', '(') # remove escaping of "(" 1456 raw_str_val = raw_str_val.replace('\)', ')') # remove escaping of ")" 1457 1458 # by now raw_str_val should contain the actual 1459 # string value, albeit encoded as UTF-16, so 1460 # decode it into a unicode object, 1461 # split multi-line fields on "\n" literal 1462 raw_str_lines = raw_str_val.split('\x00\\n') 1463 value_template_lines = [] 1464 for raw_str_line in raw_str_lines: 1465 value_template_lines.append(raw_str_line.decode('utf_16_be')) 1466 1467 replaced_lines = [] 1468 for value_template in value_template_lines: 1469 # find any placeholders within 1470 placeholders_in_value = regex.findall(data_source.placeholder_regex, value_template, regex.IGNORECASE) 1471 for placeholder in placeholders_in_value: 1472 try: 1473 replacement = data_source[placeholder] 1474 except: 1475 _log.exception(replacement) 1476 replacement = _('error with placeholder [%s]') % placeholder 1477 if replacement is None: 1478 replacement = _('error with placeholder [%s]') % placeholder 1479 value_template = value_template.replace(placeholder, replacement) 1480 1481 value_template = value_template.encode('utf_16_be') 1482 1483 if len(placeholders_in_value) > 0: 1484 value_template = value_template.replace(r'(', r'\(') 1485 value_template = value_template.replace(r')', r'\)') 1486 1487 replaced_lines.append(value_template) 1488 1489 replaced_line = '\x00\\n'.join(replaced_lines) 1490 1491 fdf_replaced_file.write('/V (') 1492 fdf_replaced_file.write(codecs.BOM_UTF16_BE) 1493 fdf_replaced_file.write(replaced_line) 1494 fdf_replaced_file.write(')\n') 1495 1496 fdf_replaced_file.close() 1497 fdf_dumped_file.close() 1498 1499 # merge replaced data back into form 1500 cmd_line = [ 1501 self.pdftk_binary, 1502 self.template_filename, 1503 r'fill_form', 1504 self.fdf_replaced_filename, 1505 r'output', 1506 self.pdf_filled_filename 1507 ] 1508 _log.debug(u' '.join(cmd_line)) 1509 try: 1510 pdftk = subprocess.Popen(cmd_line) 1511 except OSError: 1512 _log.exception('cannot run <pdftk> (merge data into form)') 1513 gmDispatcher.send(signal = u'statustext', msg = _('Error running pdftk. Cannot fill in PDF form template.'), beep = True) 1514 return False 1515 1516 pdftk.communicate() 1517 if pdftk.returncode != 0: 1518 _log.error('<pdftk> returned [%s], failed to merge FDF data into PDF form', pdftk.returncode) 1519 return False 1520 1521 return True1522 #--------------------------------------------------------1524 mimetypes = [ 1525 u'application/pdf', 1526 u'application/x-pdf' 1527 ] 1528 1529 for mimetype in mimetypes: 1530 editor_cmd = gmMimeLib.get_editor_cmd(mimetype, self.pdf_filled_filename) 1531 if editor_cmd is not None: 1532 break 1533 1534 if editor_cmd is None: 1535 _log.debug('editor cmd not found, trying viewer cmd') 1536 for mimetype in mimetypes: 1537 editor_cmd = gmMimeLib.get_viewer_cmd(mimetype, self.pdf_filled_filename) 1538 if editor_cmd is not None: 1539 break 1540 1541 if editor_cmd is None: 1542 return False 1543 1544 result = gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = True) 1545 1546 path, fname = os.path.split(self.pdf_filled_filename) 1547 candidate = os.path.join(gmTools.gmPaths().home_dir, fname) 1548 1549 if os.access(candidate, os.R_OK): 1550 _log.debug('filled-in PDF found: %s', candidate) 1551 os.rename(self.pdf_filled_filename, self.pdf_filled_filename + '.bak') 1552 shutil.move(candidate, path) 1553 else: 1554 _log.debug('filled-in PDF not found: %s', candidate) 1555 1556 self.re_editable_filenames = [self.pdf_filled_filename] 1557 1558 return result1559 #--------------------------------------------------------1561 """Generate output suitable for further processing outside this class, e.g. printing.""" 1562 1563 # eventually flatten the filled in form so we 1564 # can keep both a flattened and an editable copy: 1565 cmd_line = [ 1566 self.pdftk_binary, 1567 self.pdf_filled_filename, 1568 r'output', 1569 self.pdf_flattened_filename, 1570 r'flatten' 1571 ] 1572 _log.debug(u' '.join(cmd_line)) 1573 try: 1574 pdftk = subprocess.Popen(cmd_line) 1575 except OSError: 1576 _log.exception('cannot run <pdftk> (flatten filled in form)') 1577 gmDispatcher.send(signal = u'statustext', msg = _('Error running pdftk. Cannot flatten filled in PDF form.'), beep = True) 1578 return None 1579 1580 pdftk.communicate() 1581 if pdftk.returncode != 0: 1582 _log.error('<pdftk> returned [%s], failed to flatten filled in PDF form', pdftk.returncode) 1583 return None 1584 1585 self.final_output_filenames = [self.pdf_flattened_filename] 1586 1587 return self.pdf_flattened_filename1595 """A forms engine wrapping LaTeX. 1596 """ 16001653 1654 1655 1656 1657 #================================================================ 1658 # define a class for HTML forms (for printing) 1659 #================================================================1602 try: 1603 latex = Cheetah.Template.Template (self.template, filter=LaTeXFilter, searchList=[params]) 1604 # create a 'sandbox' directory for LaTeX to play in 1605 self.tmp = tempfile.mktemp () 1606 os.makedirs (self.tmp) 1607 self.oldcwd = os.getcwd () 1608 os.chdir (self.tmp) 1609 stdin = os.popen ("latex", "w", 2048) 1610 stdin.write (str (latex)) #send text. LaTeX spits it's output into stdout 1611 # FIXME: send LaTeX output to the logger 1612 stdin.close () 1613 if not gmShellAPI.run_command_in_shell("dvips texput.dvi -o texput.ps", blocking=True): 1614 raise FormError ('DVIPS returned error') 1615 except EnvironmentError, e: 1616 _log.error(e.strerror) 1617 raise FormError (e.strerror) 1618 return file ("texput.ps")16191621 """ 1622 For testing purposes, runs Xdvi on the intermediate TeX output 1623 WARNING: don't try this on Windows 1624 """ 1625 gmShellAPI.run_command_in_shell("xdvi texput.dvi", blocking=True)16261628 if "%F" in command: 1629 command.replace ("%F", "texput.ps") 1630 else: 1631 command = "%s < texput.ps" % command 1632 try: 1633 if not gmShellAPI.run_command_in_shell(command, blocking=True): 1634 _log.error("external command %s returned non-zero" % command) 1635 raise FormError ('external command %s returned error' % command) 1636 except EnvironmentError, e: 1637 _log.error(e.strerror) 1638 raise FormError (e.strerror) 1639 return True16401642 command, set1 = gmCfg.getDBParam (workplace = self.workplace, option = 'main.comms.print') 1643 self.exe (command)16441661 """This class can create XML document from requested data, 1662 then process it with XSLT template and display results 1663 """ 1664 1665 # FIXME: make the path configurable ? 1666 _preview_program = u'oowriter ' #this program must be in the system PATH 16671744 1745 1746 #===================================================== 1747 #class LaTeXFilter(Cheetah.Filters.Filter):1669 1670 if template is None: 1671 raise ValueError(u'%s: cannot create form instance without a template' % __name__) 1672 1673 cFormEngine.__init__(self, template = template) 1674 1675 self._FormData = None 1676 1677 # here we know/can assume that the template was stored as a utf-8 1678 # encoded string so use that conversion to create unicode: 1679 #self._XSLTData = unicode(str(template.template_data), 'UTF-8') 1680 # but in fact, unicode() knows how to handle buffers, so simply: 1681 self._XSLTData = unicode(self.template.template_data, 'UTF-8', 'strict') 1682 1683 # we must still devise a method of extracting the SQL query: 1684 # - either by retrieving it from a particular tag in the XSLT or 1685 # - by making the stored template actually be a dict which, unpickled, 1686 # has the keys "xslt" and "sql" 1687 self._SQL_query = u'select 1' #this sql query must output valid xml1688 #-------------------------------------------------------- 1689 # external API 1690 #--------------------------------------------------------1692 """get data from backend and process it with XSLT template to produce readable output""" 1693 1694 # extract SQL (this is wrong but displays what is intended) 1695 xslt = libxml2.parseDoc(self._XSLTData) 1696 root = xslt.children 1697 for child in root: 1698 if child.type == 'element': 1699 self._SQL_query = child.content 1700 break 1701 1702 # retrieve data from backend 1703 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': self._SQL_query, 'args': sql_parameters}], get_col_idx = False) 1704 1705 __header = '<?xml version="1.0" encoding="UTF-8"?>\n' 1706 __body = rows[0][0] 1707 1708 # process XML data according to supplied XSLT, producing HTML 1709 self._XMLData =__header + __body 1710 style = libxslt.parseStylesheetDoc(xslt) 1711 xml = libxml2.parseDoc(self._XMLData) 1712 html = style.applyStylesheet(xml, None) 1713 self._FormData = html.serialize() 1714 1715 style.freeStylesheet() 1716 xml.freeDoc() 1717 html.freeDoc()1718 #--------------------------------------------------------1720 if self._FormData is None: 1721 raise ValueError, u'Preview request for empty form. Make sure the form is properly initialized and process() was performed' 1722 1723 fname = gmTools.get_unique_filename(prefix = u'gm_XSLT_form-', suffix = u'.html') 1724 #html_file = os.open(fname, 'wb') 1725 #html_file.write(self._FormData.encode('UTF-8')) 1726 html_file = codecs.open(fname, 'wb', 'utf8', 'strict') # or 'replace' ? 1727 html_file.write(self._FormData) 1728 html_file.close() 1729 1730 cmd = u'%s %s' % (self.__class__._preview_program, fname) 1731 1732 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = False): 1733 _log.error('%s: cannot launch report preview program' % __name__) 1734 return False 1735 1736 #os.unlink(self.filename) #delete file 1737 #FIXME: under Windows the temp file is deleted before preview program gets it (under Linux it works OK) 1738 1739 return True1740 #--------------------------------------------------------1787 1788 1789 #=========================================================== 1792 1793 #============================================================ 1794 # convenience functions 1795 #------------------------------------------------------------1750 """ 1751 Convience function to escape ISO-Latin-1 strings for TeX output 1752 WARNING: not all ISO-Latin-1 characters are expressible in TeX 1753 FIXME: nevertheless, there are a few more we could support 1754 1755 Also intelligently convert lists and tuples into TeX-style table lines 1756 """ 1757 if type (item) is types.UnicodeType or type (item) is types.StringType: 1758 item = item.replace ("\\", "\\backslash") # I wonder about this, do we want users to be able to use raw TeX? 1759 item = item.replace ("&", "\\&") 1760 item = item.replace ("$", "\\$") 1761 item = item.replace ('"', "") # okay, that's not right, but easiest solution for now 1762 item = item.replace ("\n", "\\\\ ") 1763 if len (item.strip ()) == 0: 1764 item = "\\relax " # sometimes TeX really hates empty strings, this seems to mollify it 1765 # FIXME: cover all of ISO-Latin-1 which can be expressed in TeX 1766 if type (item) is types.UnicodeType: 1767 item = item.encode ('latin-1', 'replace') 1768 trans = {'ß':'\\ss{}', 'ä': '\\"{a}', 'Ä' :'\\"{A}', 'ö': '\\"{o}', 'Ö': '\\"{O}', 'ü': '\\"{u}', 'Ü': '\\"{U}', 1769 '\x8a':'\\v{S}', '\x8a':'\\OE{}', '\x9a':'\\v{s}', '\x9c': '\\oe{}', '\a9f':'\\"{Y}', #Microsloth extensions 1770 '\x86': '{\\dag}', '\x87': '{\\ddag}', '\xa7':'{\\S}', '\xb6': '{\\P}', '\xa9': '{\\copyright}', '\xbf': '?`', 1771 '\xc0':'\\`{A}', '\xa1': "\\'{A}", '\xa2': '\\^{A}', '\xa3':'\\~{A}', '\\xc5': '{\AA}', 1772 '\xc7':'\\c{C}', '\xc8':'\\`{E}', 1773 '\xa1': '!`', 1774 '\xb5':'$\mu$', '\xa3': '\pounds{}', '\xa2':'cent'} 1775 for k, i in trans.items (): 1776 item = item.replace (k, i) 1777 elif type (item) is types.ListType or type (item) is types.TupleType: 1778 item = string.join ([self.filter (i, ' & ') for i in item], table_sep) 1779 elif item is None: 1780 item = '\\relax % Python None\n' 1781 elif type (item) is types.IntType or type (item) is types.FloatType: 1782 item = str (item) 1783 else: 1784 item = str (item) 1785 _log.warning("unknown type %s, string %s" % (type (item), item)) 1786 return item1797 """ 1798 Instantiates a FormEngine based on the form ID or name from the backend 1799 """ 1800 try: 1801 # it's a number: match to form ID 1802 id = int (id) 1803 cmd = 'select template, engine, pk from paperwork_templates where pk = %s' 1804 except ValueError: 1805 # it's a string, match to the form's name 1806 # FIXME: can we somehow OR like this: where name_short=%s OR name_long=%s ? 1807 cmd = 'select template, engine, flags, pk from paperwork_templates where name_short = %s' 1808 result = gmPG.run_ro_query ('reference', cmd, None, id) 1809 if result is None: 1810 _log.error('error getting form [%s]' % id) 1811 raise gmExceptions.FormError ('error getting form [%s]' % id) 1812 if len(result) == 0: 1813 _log.error('no form [%s] found' % id) 1814 raise gmExceptions.FormError ('no such form found [%s]' % id) 1815 if result[0][1] == 'L': 1816 return LaTeXForm (result[0][2], result[0][0]) 1817 elif result[0][1] == 'T': 1818 return TextForm (result[0][2], result[0][0]) 1819 else: 1820 _log.error('no form engine [%s] for form [%s]' % (result[0][1], id)) 1821 raise FormError ('no engine [%s] for form [%s]' % (result[0][1], id))1822 #------------------------------------------------------------- 1829 #------------------------------------------------------------- 1830 1831 test_letter = """ 1832 \\documentclass{letter} 1833 \\address{ $DOCTOR \\\\ 1834 $DOCTORADDRESS} 1835 \\signature{$DOCTOR} 1836 1837 \\begin{document} 1838 \\begin{letter}{$RECIPIENTNAME \\\\ 1839 $RECIPIENTADDRESS} 1840 1841 \\opening{Dear $RECIPIENTNAME} 1842 1843 \\textbf{Re:} $PATIENTNAME, DOB: $DOB, $PATIENTADDRESS \\\\ 1844 1845 $TEXT 1846 1847 \\ifnum$INCLUDEMEDS>0 1848 \\textbf{Medications List} 1849 1850 \\begin{tabular}{lll} 1851 $MEDSLIST 1852 \\end{tabular} 1853 \\fi 1854 1855 \\ifnum$INCLUDEDISEASES>0 1856 \\textbf{Disease List} 1857 1858 \\begin{tabular}{l} 1859 $DISEASELIST 1860 \\end{tabular} 1861 \\fi 1862 1863 \\closing{$CLOSING} 1864 1865 \\end{letter} 1866 \\end{document} 1867 """ 1868 18691871 f = open('../../test-area/ian/terry-form.tex') 1872 params = { 1873 'RECIPIENT': "Dr. R. Terry\n1 Main St\nNewcastle", 1874 'DOCTORSNAME': 'Ian Haywood', 1875 'DOCTORSADDRESS': '1 Smith St\nMelbourne', 1876 'PATIENTNAME':'Joe Bloggs', 1877 'PATIENTADDRESS':'18 Fred St\nMelbourne', 1878 'REQUEST':'echocardiogram', 1879 'THERAPY':'on warfarin', 1880 'CLINICALNOTES':"""heard new murmur 1881 Here's some 1882 crap to demonstrate how it can cover multiple lines.""", 1883 'COPYADDRESS':'Karsten Hilbert\nLeipzig, Germany', 1884 'ROUTINE':1, 1885 'URGENT':0, 1886 'FAX':1, 1887 'PHONE':1, 1888 'PENSIONER':1, 1889 'VETERAN':0, 1890 'PADS':0, 1891 'INSTRUCTIONS':u'Take the blue pill, Neo' 1892 } 1893 form = LaTeXForm (1, f.read()) 1894 form.process (params) 1895 form.xdvi () 1896 form.cleanup ()18971899 form = LaTeXForm (2, test_letter) 1900 params = {'RECIPIENTNAME':'Dr. Richard Terry', 1901 'RECIPIENTADDRESS':'1 Main St\nNewcastle', 1902 'DOCTOR':'Dr. Ian Haywood', 1903 'DOCTORADDRESS':'1 Smith St\nMelbourne', 1904 'PATIENTNAME':'Joe Bloggs', 1905 'PATIENTADDRESS':'18 Fred St, Melbourne', 1906 'TEXT':"""This is the main text of the referral letter""", 1907 'DOB':'12/3/65', 1908 'INCLUDEMEDS':1, 1909 'MEDSLIST':[["Amoxycillin", "500mg", "TDS"], ["Perindopril", "4mg", "OD"]], 1910 'INCLUDEDISEASES':0, 'DISEASELIST':'', 1911 'CLOSING':'Yours sincerely,' 1912 } 1913 form.process (params) 1914 print os.getcwd () 1915 form.xdvi () 1916 form.cleanup ()1917 #------------------------------------------------------------1919 template = open('../../test-area/ian/Formularkopf-DE.tex') 1920 form = LaTeXForm(template=template.read()) 1921 params = { 1922 'PATIENT LASTNAME': 'Kirk', 1923 'PATIENT FIRSTNAME': 'James T.', 1924 'PATIENT STREET': 'Hauptstrasse', 1925 'PATIENT ZIP': '02999', 1926 'PATIENT TOWN': 'Gross Saerchen', 1927 'PATIENT DOB': '22.03.1931' 1928 } 1929 form.process(params) 1930 form.xdvi() 1931 form.cleanup()1932 1933 #============================================================ 1934 # main 1935 #------------------------------------------------------------ 1936 if __name__ == '__main__': 1937 1938 if len(sys.argv) < 2: 1939 sys.exit() 1940 1941 if sys.argv[1] != 'test': 1942 sys.exit() 1943 1944 from Gnumed.pycommon import gmDateTime 1945 gmDateTime.init() 1946 1947 #-------------------------------------------------------- 1948 # OOo 1949 #--------------------------------------------------------1951 init_ooo()1952 #-------------------------------------------------------- 1957 #--------------------------------------------------------1959 srv = gmOOoConnector() 1960 doc = srv.open_document(filename = sys.argv[2]) 1961 print "document:", doc1962 #--------------------------------------------------------1964 doc = cOOoLetter(template_file = sys.argv[2]) 1965 doc.open_in_ooo() 1966 print "document:", doc 1967 raw_input('press <ENTER> to continue') 1968 doc.show() 1969 #doc.replace_placeholders() 1970 #doc.save_in_ooo('~/test_cOOoLetter.odt') 1971 # doc = None 1972 # doc.close_in_ooo() 1973 raw_input('press <ENTER> to continue')1974 #--------------------------------------------------------1976 try: 1977 doc = open_uri_in_ooo(filename=sys.argv[1]) 1978 except: 1979 _log.exception('cannot open [%s] in OOo' % sys.argv[1]) 1980 raise 1981 1982 class myCloseListener(unohelper.Base, oooXCloseListener): 1983 def disposing(self, evt): 1984 print "disposing:"1985 def notifyClosing(self, evt): 1986 print "notifyClosing:" 1987 def queryClosing(self, evt, owner): 1988 # owner is True/False whether I am the owner of the doc 1989 print "queryClosing:" 1990 1991 l = myCloseListener() 1992 doc.addCloseListener(l) 1993 1994 tfs = doc.getTextFields().createEnumeration() 1995 print tfs 1996 print dir(tfs) 1997 while tfs.hasMoreElements(): 1998 tf = tfs.nextElement() 1999 if tf.supportsService('com.sun.star.text.TextField.JumpEdit'): 2000 print tf.getPropertyValue('PlaceHolder') 2001 print " ", tf.getPropertyValue('Hint') 2002 2003 # doc.close(True) # closes but leaves open the dedicated OOo window 2004 doc.dispose() # closes and disposes of the OOo window 2005 #--------------------------------------------------------2007 pat = gmPersonSearch.ask_for_patient() 2008 if pat is None: 2009 return 2010 gmPerson.set_active_patient(patient = pat) 2011 2012 doc = cOOoLetter(template_file = sys.argv[2]) 2013 doc.open_in_ooo() 2014 print doc 2015 doc.show() 2016 #doc.replace_placeholders() 2017 #doc.save_in_ooo('~/test_cOOoLetter.odt') 2018 doc = None 2019 # doc.close_in_ooo() 2020 raw_input('press <ENTER> to continue')2021 #-------------------------------------------------------- 2022 # other 2023 #--------------------------------------------------------2025 template = cFormTemplate(aPK_obj = sys.argv[2]) 2026 print template 2027 print template.export_to_file()2028 #--------------------------------------------------------2030 template = cFormTemplate(aPK_obj = sys.argv[2]) 2031 template.update_template_from_file(filename = sys.argv[3])2032 #--------------------------------------------------------2034 pat = gmPersonSearch.ask_for_patient() 2035 if pat is None: 2036 return 2037 gmPerson.set_active_patient(patient = pat) 2038 2039 gmStaff.gmCurrentProvider(provider = gmStaff.cStaff()) 2040 2041 path = os.path.abspath(sys.argv[2]) 2042 form = cLaTeXForm(template_file = path) 2043 2044 from Gnumed.wxpython import gmMacro 2045 ph = gmMacro.gmPlaceholderHandler() 2046 ph.debug = True 2047 instance_file = form.substitute_placeholders(data_source = ph) 2048 pdf_name = form.generate_output(instance_file = instance_file) 2049 print "final PDF file is:", pdf_name2050 #--------------------------------------------------------2052 pat = gmPersonSearch.ask_for_patient() 2053 if pat is None: 2054 return 2055 gmPerson.set_active_patient(patient = pat) 2056 2057 gmStaff.gmCurrentProvider(provider = gmStaff.cStaff()) 2058 2059 path = os.path.abspath(sys.argv[2]) 2060 form = cPDFForm(template_file = path) 2061 2062 from Gnumed.wxpython import gmMacro 2063 ph = gmMacro.gmPlaceholderHandler() 2064 ph.debug = True 2065 instance_file = form.substitute_placeholders(data_source = ph) 2066 pdf_name = form.generate_output(instance_file = instance_file) 2067 print "final PDF file is:", pdf_name2068 #--------------------------------------------------------2070 pat = gmPersonSearch.ask_for_patient() 2071 if pat is None: 2072 return 2073 gmPerson.set_active_patient(patient = pat) 2074 2075 gmStaff.gmCurrentProvider(provider = gmStaff.cStaff()) 2076 2077 path = os.path.abspath(sys.argv[2]) 2078 form = cAbiWordForm(template_file = path) 2079 2080 from Gnumed.wxpython import gmMacro 2081 ph = gmMacro.gmPlaceholderHandler() 2082 ph.debug = True 2083 instance_file = form.substitute_placeholders(data_source = ph) 2084 form.edit() 2085 final_name = form.generate_output(instance_file = instance_file) 2086 print "final file is:", final_name2087 #--------------------------------------------------------2089 pat = gmPersonSearch.ask_for_patient() 2090 if pat is None: 2091 return 2092 gmPerson.set_active_patient(patient = pat) 2093 2094 gmStaff.gmCurrentProvider(provider = gmStaff.cStaff()) 2095 2096 path = os.path.abspath(sys.argv[2]) 2097 form = cTextForm(template_file = path) 2098 2099 from Gnumed.wxpython import gmMacro 2100 ph = gmMacro.gmPlaceholderHandler() 2101 ph.debug = True 2102 print "placeholder substitution worked:", form.substitute_placeholders(data_source = ph) 2103 form.edit() 2104 form.generate_output()2105 #-------------------------------------------------------- 2106 #-------------------------------------------------------- 2107 #-------------------------------------------------------- 2108 # now run the tests 2109 #test_au() 2110 #test_de() 2111 2112 # OOo 2113 #test_init_ooo() 2114 #test_ooo_connect() 2115 #test_open_ooo_doc_from_srv() 2116 #test_open_ooo_doc_from_letter() 2117 #play_with_ooo() 2118 #test_cOOoLetter() 2119 2120 #test_cFormTemplate() 2121 #set_template_from_file() 2122 test_latex_form() 2123 #test_pdf_form() 2124 #test_abiword_form() 2125 #test_text_form() 2126 2127 #============================================================ 2128
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Mon Jul 1 03:56:36 2013 | http://epydoc.sourceforge.net |