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