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