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 cmd = u""" 293 INSERT INTO ref.paperwork_templates ( 294 fk_template_type, 295 name_short, 296 name_long, 297 external_version 298 ) VALUES ( 299 %(type)s, 300 %(nshort)s, 301 %(nlong)s, 302 %(ext_version)s 303 ) 304 RETURNING pk 305 """ 306 args = {'type': template_type, 'nshort': name_short, 'nlong': name_long, 'ext_version': 'new'} 307 rows, idx = gmPG2.run_rw_queries(queries = [{'cmd': cmd, 'args': args}], return_data = True) 308 template = cFormTemplate(aPK_obj = rows[0][0]) 309 return template310 311 #------------------------------------------------------------313 rows, idx = gmPG2.run_rw_queries ( 314 queries = [{ 315 'cmd': u'DELETE FROM ref.paperwork_templates WHERE pk = %(pk)s', 316 'args': {'pk': template['pk_paperwork_template']} 317 }] 318 ) 319 return True320 321 #============================================================ 322 # OpenOffice/LibreOffice API 323 #============================================================ 324 uno = None 325 cOOoDocumentCloseListener = None 326 writer_binary = None 327 328 # http://forum.openoffice.org/en/forum/viewtopic.php?t=36370 329 # http://stackoverflow.com/questions/4270962/using-pyuno-with-my-existing-python-installation 330 331 #-----------------------------------------------------------333 334 try: 335 which = subprocess.Popen ( 336 args = ('which', 'soffice'), 337 stdout = subprocess.PIPE, 338 stdin = subprocess.PIPE, 339 stderr = subprocess.PIPE, 340 universal_newlines = True 341 ) 342 except (OSError, ValueError, subprocess.CalledProcessError): 343 _log.exception('there was a problem executing [which soffice]') 344 return 345 346 soffice_path, err = which.communicate() 347 soffice_path = soffice_path.strip('\n') 348 uno_path = os.path.abspath ( os.path.join ( 349 os.path.dirname(os.path.realpath(soffice_path)), 350 '..', 351 'basis-link', 352 'program' 353 )) 354 355 _log.info('UNO should be at [%s], appending to sys.path', uno_path) 356 357 sys.path.append(uno_path)358 #-----------------------------------------------------------360 """FIXME: consider this: 361 362 try: 363 import uno 364 except: 365 print "This Script needs to be run with the python from OpenOffice.org" 366 print "Example: /opt/OpenOffice.org/program/python %s" % ( 367 os.path.basename(sys.argv[0])) 368 print "Or you need to insert the right path at the top, where uno.py is." 369 print "Default: %s" % default_path 370 """ 371 global uno 372 if uno is not None: 373 return 374 375 try: 376 import uno 377 except ImportError: 378 __configure_path_to_UNO() 379 import uno 380 381 global unohelper, oooXCloseListener, oooNoConnectException, oooPropertyValue 382 383 import unohelper 384 from com.sun.star.util import XCloseListener as oooXCloseListener 385 from com.sun.star.connection import NoConnectException as oooNoConnectException 386 from com.sun.star.beans import PropertyValue as oooPropertyValue 387 388 #---------------------------------- 389 class _cOOoDocumentCloseListener(unohelper.Base, oooXCloseListener): 390 """Listens for events sent by OOo during the document closing 391 sequence and notifies the GNUmed client GUI so it can 392 import the closed document into the database. 393 """ 394 def __init__(self, document=None): 395 self.document = document396 397 def queryClosing(self, evt, owner): 398 # owner is True/False whether I am the owner of the doc 399 pass 400 401 def notifyClosing(self, evt): 402 pass 403 404 def disposing(self, evt): 405 self.document.on_disposed_by_ooo() 406 self.document = None 407 #---------------------------------- 408 409 global cOOoDocumentCloseListener 410 cOOoDocumentCloseListener = _cOOoDocumentCloseListener 411 412 # search for writer binary 413 global writer_binary 414 found, binary = gmShellAPI.find_first_binary(binaries = [ 415 'lowriter', 416 'oowriter' 417 ]) 418 if found: 419 _log.debug('OOo/LO writer binary found: %s', binary) 420 writer_binary = binary 421 else: 422 _log.debug('OOo/LO writer binary NOT found') 423 raise ImportError('LibreOffice/OpenOffice (lowriter/oowriter) not found') 424 425 _log.debug('python UNO bridge successfully initialized') 426 427 #------------------------------------------------------------429 """This class handles the connection to OOo. 430 431 Its Singleton instance stays around once initialized. 432 """ 433 # FIXME: need to detect closure of OOo !553 #------------------------------------------------------------435 436 init_ooo() 437 438 self.__setup_connection_string() 439 440 self.resolver_uri = "com.sun.star.bridge.UnoUrlResolver" 441 self.desktop_uri = "com.sun.star.frame.Desktop" 442 443 self.max_connect_attempts = 5 444 445 self.local_context = uno.getComponentContext() 446 self.uri_resolver = self.local_context.ServiceManager.createInstanceWithContext(self.resolver_uri, self.local_context) 447 448 self.__desktop = None449 #-------------------------------------------------------- 450 # external API 451 #--------------------------------------------------------453 if self.__desktop is None: 454 _log.debug('no desktop, no cleanup') 455 return 456 457 try: 458 self.__desktop.terminate() 459 except: 460 _log.exception('cannot terminate OOo desktop')461 #--------------------------------------------------------463 """<filename> must be absolute""" 464 if self.desktop is None: 465 _log.error('cannot access OOo desktop') 466 return None 467 468 filename = os.path.expanduser(filename) 469 filename = os.path.abspath(filename) 470 document_uri = uno.systemPathToFileUrl(filename) 471 472 _log.debug('%s -> %s', filename, document_uri) 473 474 doc = self.desktop.loadComponentFromURL(document_uri, "_blank", 0, ()) 475 return doc476 #-------------------------------------------------------- 477 # internal helpers 478 #--------------------------------------------------------480 # later factor this out ! 481 dbcfg = gmCfg.cCfgSQL() 482 self.ooo_startup_settle_time = dbcfg.get2 ( 483 option = u'external.ooo.startup_settle_time', 484 workplace = gmPraxis.gmCurrentPraxisBranch().active_workplace, 485 bias = u'workplace', 486 default = 3.0 487 )488 #--------------------------------------------------------490 491 # socket: 492 # ooo_port = u'2002' 493 # #self.ooo_start_cmd = 'oowriter -invisible -norestore -nofirststartwizard -nologo -accept="socket,host=localhost,port=%s;urp;StarOffice.ServiceManager"' % ooo_port 494 # self.ooo_start_cmd = 'oowriter -invisible -norestore -accept="socket,host=localhost,port=%s;urp;"' % ooo_port 495 # self.remote_context_uri = "uno:socket,host=localhost,port=%s;urp;StarOffice.ComponentContext" % ooo_port 496 497 # pipe: 498 pipe_name = "uno-gm2lo-%s" % str(random.random())[2:] 499 _log.debug('expecting OOo/LO server on named pipe [%s]', pipe_name) 500 self.ooo_start_cmd = '%s --invisible --norestore --accept="pipe,name=%s;urp" &' % ( 501 writer_binary, 502 pipe_name 503 ) 504 _log.debug('startup command: %s', self.ooo_start_cmd) 505 506 self.remote_context_uri = "uno:pipe,name=%s;urp;StarOffice.ComponentContext" % pipe_name 507 _log.debug('remote context URI: %s', self.remote_context_uri)508 #--------------------------------------------------------510 _log.info('trying to start OOo server') 511 _log.debug('startup command: %s', self.ooo_start_cmd) 512 os.system(self.ooo_start_cmd) 513 self.__get_startup_settle_time() 514 _log.debug('waiting %s seconds for OOo to start up', self.ooo_startup_settle_time) 515 time.sleep(self.ooo_startup_settle_time)516 #-------------------------------------------------------- 517 # properties 518 #--------------------------------------------------------520 if self.__desktop is not None: 521 return self.__desktop 522 523 self.remote_context = None 524 525 attempts = self.max_connect_attempts 526 while attempts > 0: 527 528 _log.debug(u'attempt %s/%s', self.max_connect_attempts - attempts + 1, self.max_connect_attempts) 529 530 try: 531 self.remote_context = self.uri_resolver.resolve(self.remote_context_uri) 532 break 533 except oooNoConnectException: 534 _log.exception('cannot connect to OOo') 535 536 # first loop ? 537 if attempts == self.max_connect_attempts: 538 self.__startup_ooo() 539 else: 540 time.sleep(1) 541 542 attempts = attempts - 1 543 544 if self.remote_context is None: 545 raise OSError(-1, u'cannot connect to OpenOffice', self.remote_context_uri) 546 547 _log.debug('connection seems established') 548 self.__desktop = self.remote_context.ServiceManager.createInstanceWithContext(self.desktop_uri, self.remote_context) 549 _log.debug('got OOo desktop handle') 550 return self.__desktop551 552 desktop = property(_get_desktop, lambda x:x)555660 #-------------------------------------------------------- 661 # internal helpers 662 #-------------------------------------------------------- 663 664 #============================================================557 558 self.template_file = template_file 559 self.instance_type = instance_type 560 self.ooo_doc = None561 #-------------------------------------------------------- 562 # external API 563 #--------------------------------------------------------565 # connect to OOo 566 ooo_srv = gmOOoConnector() 567 568 # open doc in OOo 569 self.ooo_doc = ooo_srv.open_document(filename = self.template_file) 570 if self.ooo_doc is None: 571 _log.error('cannot open document in OOo') 572 return False 573 574 # listen for close events 575 pat = gmPerson.gmCurrentPatient() 576 pat.locked = True 577 listener = cOOoDocumentCloseListener(document = self) 578 self.ooo_doc.addCloseListener(listener) 579 580 return True581 #-------------------------------------------------------- 584 #--------------------------------------------------------586 587 # new style embedded, implicit placeholders 588 searcher = self.ooo_doc.createSearchDescriptor() 589 searcher.SearchCaseSensitive = False 590 searcher.SearchRegularExpression = True 591 searcher.SearchWords = True 592 searcher.SearchString = handler.placeholder_regex 593 594 placeholder_instance = self.ooo_doc.findFirst(searcher) 595 while placeholder_instance is not None: 596 try: 597 val = handler[placeholder_instance.String] 598 except: 599 val = _('error with placeholder [%s]') % placeholder_instance.String 600 _log.exception(val) 601 602 if val is None: 603 val = _('error with placeholder [%s]') % placeholder_instance.String 604 605 placeholder_instance.String = val 606 placeholder_instance = self.ooo_doc.findNext(placeholder_instance.End, searcher) 607 608 if not old_style_too: 609 return 610 611 # old style "explicit" placeholders 612 text_fields = self.ooo_doc.getTextFields().createEnumeration() 613 while text_fields.hasMoreElements(): 614 text_field = text_fields.nextElement() 615 616 # placeholder ? 617 if not text_field.supportsService('com.sun.star.text.TextField.JumpEdit'): 618 continue 619 # placeholder of type text ? 620 if text_field.PlaceHolderType != 0: 621 continue 622 623 replacement = handler[text_field.PlaceHolder] 624 if replacement is None: 625 continue 626 627 text_field.Anchor.setString(replacement)628 #--------------------------------------------------------630 if filename is not None: 631 target_url = uno.systemPathToFileUrl(os.path.abspath(os.path.expanduser(filename))) 632 save_args = ( 633 oooPropertyValue('Overwrite', 0, True, 0), 634 oooPropertyValue('FormatFilter', 0, 'swriter: StarOffice XML (Writer)', 0) 635 636 ) 637 # "store AS url" stores the doc, marks it unmodified and updates 638 # the internal media descriptor - as opposed to "store TO url" 639 self.ooo_doc.storeAsURL(target_url, save_args) 640 else: 641 self.ooo_doc.store()642 #--------------------------------------------------------644 self.ooo_doc.dispose() 645 pat = gmPerson.gmCurrentPatient() 646 pat.locked = False 647 self.ooo_doc = None648 #--------------------------------------------------------650 # get current file name from OOo, user may have used Save As 651 filename = uno.fileUrlToSystemPath(self.ooo_doc.URL) 652 # tell UI to import the file 653 gmDispatcher.send ( 654 signal = u'import_document_from_file', 655 filename = filename, 656 document_type = self.instance_type, 657 unlock_patient = True 658 ) 659 self.ooo_doc = None666 """Ancestor for forms.""" 667684 #-------------------------------------------------------- 685 #-------------------------------------------------------- 686 # def process(self, data_source=None): 687 # """Merge values into the form template. 688 # """ 689 # pass 690 # #-------------------------------------------------------- 691 # def cleanup(self): 692 # """ 693 # A sop to TeX which can't act as a true filter: to delete temporary files 694 # """ 695 # pass 696 # #-------------------------------------------------------- 697 # def exe(self, command): 698 # """ 699 # Executes the provided command. 700 # If command cotains %F. it is substituted with the filename 701 # Otherwise, the file is fed in on stdin 702 # """ 703 # pass 704 # #-------------------------------------------------------- 705 # def store(self, params=None): 706 # """Stores the parameters in the backend. 707 # 708 # - link_obj can be a cursor, a connection or a service name 709 # - assigning a cursor to link_obj allows the calling code to 710 # group the call to store() into an enclosing transaction 711 # (for an example see gmReferral.send_referral()...) 712 # """ 713 # # some forms may not have values ... 714 # if params is None: 715 # params = {} 716 # patient_clinical = self.patient.get_emr() 717 # encounter = patient_clinical.active_encounter['pk_encounter'] 718 # # FIXME: get_active_episode is no more 719 # #episode = patient_clinical.get_active_episode()['pk_episode'] 720 # # generate "forever unique" name 721 # cmd = "select name_short || ': <' || name_long || '::' || external_version || '>' from paperwork_templates where pk=%s"; 722 # rows = gmPG.run_ro_query('reference', cmd, None, self.pk_def) 723 # form_name = None 724 # if rows is None: 725 # _log.error('error retrieving form def for [%s]' % self.pk_def) 726 # elif len(rows) == 0: 727 # _log.error('no form def for [%s]' % self.pk_def) 728 # else: 729 # form_name = rows[0][0] 730 # # we didn't get a name but want to store the form anyhow 731 # if form_name is None: 732 # form_name=time.time() # hopefully unique enough 733 # # in one transaction 734 # queries = [] 735 # # - store form instance in form_instance 736 # cmd = "insert into form_instances(fk_form_def, form_name, fk_episode, fk_encounter) values (%s, %s, %s, %s)" 737 # queries.append((cmd, [self.pk_def, form_name, episode, encounter])) 738 # # - store params in form_data 739 # for key in params.keys(): 740 # cmd = """ 741 # insert into form_data(fk_instance, place_holder, value) 742 # values ((select currval('form_instances_pk_seq')), %s, %s::text) 743 # """ 744 # queries.append((cmd, [key, params[key]])) 745 # # - get inserted PK 746 # queries.append(("select currval ('form_instances_pk_seq')", [])) 747 # status, err = gmPG.run_commit('historica', queries, True) 748 # if status is None: 749 # _log.error('failed to store form [%s] (%s): %s' % (self.pk_def, form_name, err)) 750 # return None 751 # return status 752 753 #================================================================ 754 # OOo template forms 755 #----------------------------------------------------------------669 self.template = None 670 self.template_filename = template_file 671 _log.debug('working on template file [%s]', self.template_filename)672 #--------------------------------------------------------674 """Parse the template into an instance and replace placeholders with values.""" 675 raise NotImplementedError676 #-------------------------------------------------------- 680 #--------------------------------------------------------757 """A forms engine wrapping OOo.""" 758766 767 #================================================================ 768 # AbiWord template forms 769 #----------------------------------------------------------------760 super(self.__class__, self).__init__(template_file = template_file) 761 762 path, ext = os.path.splitext(self.template_filename) 763 if ext in [r'', r'.']: 764 ext = r'.odt' 765 self.instance_filename = r'%s-instance%s' % (path, ext)771 """A forms engine wrapping AbiWord.""" 772 773 placeholder_regex = r'\$<.+?>\$' 774872 873 #---------------------------------------------------------------- 874 form_engines[u'A'] = cAbiWordForm 875 876 #================================================================ 877 # text template forms 878 #----------------------------------------------------------------776 777 super(cAbiWordForm, self).__init__(template_file = template_file) 778 779 # detect abiword 780 found, self.abiword_binary = gmShellAPI.detect_external_binary(binary = r'abiword') 781 if not found: 782 raise ImportError('<abiword(.exe)> not found')783 #--------------------------------------------------------785 # should *actually* properly parse the XML 786 787 path, ext = os.path.splitext(self.template_filename) 788 if ext in [r'', r'.']: 789 ext = r'.abw' 790 self.instance_filename = r'%s-instance%s' % (path, ext) 791 792 template_file = codecs.open(self.template_filename, 'rU', 'utf8') 793 instance_file = codecs.open(self.instance_filename, 'wb', 'utf8') 794 795 if self.template is not None: 796 # inject placeholder values 797 data_source.set_placeholder(u'form_name_long', self.template['name_long']) 798 data_source.set_placeholder(u'form_name_short', self.template['name_short']) 799 data_source.set_placeholder(u'form_version', self.template['external_version']) 800 801 data_source.escape_style = u'xml' 802 data_source.escape_function = None # gmTools.xml_escape_text() ? 803 804 for line in template_file: 805 806 if line.strip() in [u'', u'\r', u'\n', u'\r\n']: 807 instance_file.write(line) 808 continue 809 810 # 1) find placeholders in this line 811 placeholders_in_line = regex.findall(cAbiWordForm.placeholder_regex, line, regex.IGNORECASE) 812 # 2) and replace them 813 for placeholder in placeholders_in_line: 814 try: 815 val = data_source[placeholder.replace(u'<', u'<').replace(u'>', u'>')] 816 except: 817 val = _('error with placeholder [%s]') % gmTools.xml_escape_string(placeholder) 818 _log.exception(val) 819 820 if val is None: 821 val = _('error with placeholder [%s]') % gmTools.xml_escape_string(placeholder) 822 823 line = line.replace(placeholder, val) 824 825 instance_file.write(line) 826 827 instance_file.close() 828 template_file.close() 829 830 if self.template is not None: 831 # remove temporary placeholders 832 data_source.unset_placeholder(u'form_name_long') 833 data_source.unset_placeholder(u'form_name_short') 834 data_source.unset_placeholder(u'form_version') 835 836 return837 #--------------------------------------------------------839 enc = sys.getfilesystemencoding() 840 cmd = (r'%s %s' % (self.abiword_binary, self.instance_filename.encode(enc))).encode(enc) 841 result = gmShellAPI.run_command_in_shell(command = cmd, blocking = True) 842 self.re_editable_filenames = [self.instance_filename] 843 return result844 #--------------------------------------------------------846 847 if instance_file is None: 848 instance_file = self.instance_filename 849 try: 850 open(instance_file, 'r').close() 851 except: 852 _log.exception('cannot access form instance file [%s]', instance_file) 853 gmLog2.log_stack_trace() 854 return None 855 self.instance_filename = instance_file 856 857 _log.debug('ignoring <format> directive [%s], generating PDF', format) 858 859 pdf_name = os.path.splitext(self.instance_filename)[0] + u'.pdf' 860 cmd = u'%s --to=pdf --to-name=%s %s' % ( 861 self.abiword_binary, 862 pdf_name, 863 self.instance_filename 864 ) 865 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = True): 866 _log.error('problem running abiword, cannot generate form output') 867 gmDispatcher.send(signal = 'statustext', msg = _('Error running AbiWord. Cannot turn generate PDF.'), beep = True) 868 return None 869 870 self.final_output_filenames = [pdf_name] 871 return pdf_name880 """A forms engine outputting data as text for further processing.""" 881975 #------------------------------------------------------------ 976 form_engines[u'T'] = cTextForm 977 978 #================================================================ 979 # LaTeX template forms 980 #----------------------------------------------------------------883 super(self.__class__, self).__init__(template_file = template_file) 884 885 # generate real template file from .ini file 886 cfg_file = codecs.open(filename = self.template_filename, mode = 'rU', encoding = u'utf8') 887 self.form_definition = gmCfg2.parse_INI_stream(stream = cfg_file) 888 cfg_file.close() 889 self.form_definition['form::template']890 #--------------------------------------------------------892 self.instance_filename = gmTools.get_unique_filename ( 893 prefix = 'gm-T-instance-', 894 suffix = '.txt' 895 ) 896 instance_file = codecs.open(self.instance_filename, 'wb', 'utf8') 897 898 if self.template is not None: 899 # inject placeholder values 900 data_source.set_placeholder(u'form_name_long', self.template['name_long']) 901 data_source.set_placeholder(u'form_name_short', self.template['name_short']) 902 data_source.set_placeholder(u'form_version', self.template['external_version']) 903 904 if isinstance(self.form_definition['form::template'], type([])): 905 template_text = self.form_definition['form::template'] 906 else: 907 template_text = self.form_definition['form::template'].split('\n') 908 909 no_errors = True 910 for line in template_text: 911 if line.strip() in [u'', u'\r', u'\n', u'\r\n']: 912 instance_file.write('%s\n' % line) 913 continue 914 915 # 1) find placeholders in this line 916 placeholders_in_line = regex.findall(data_source.placeholder_regex, line, regex.IGNORECASE) 917 # 2) and replace them 918 for placeholder in placeholders_in_line: 919 try: 920 val = data_source[placeholder] 921 except: 922 val = _('error with placeholder [%s]') % placeholder 923 _log.exception(val) 924 no_errors = False 925 926 if val is None: 927 val = _('error with placeholder [%s]') % placeholder 928 929 line = line.replace(placeholder, val) 930 931 instance_file.write(u'%s\n' % line) 932 933 instance_file.close() 934 self.re_editable_filenames = [self.instance_filename] 935 936 if self.template is not None: 937 # remove temporary placeholders 938 data_source.unset_placeholder(u'form_name_long') 939 data_source.unset_placeholder(u'form_name_short') 940 data_source.unset_placeholder(u'form_version') 941 942 return no_errors943 #--------------------------------------------------------945 946 editor_cmd = None 947 try: 948 editor_cmd = self.form_definition['form::editor'] % self.instance_filename 949 except KeyError: 950 _log.debug('no explicit editor defined for text template') 951 952 if editor_cmd is None: 953 mimetype = u'text/plain' 954 editor_cmd = gmMimeLib.get_editor_cmd(mimetype, self.instance_filename) 955 if editor_cmd is None: 956 # also consider text *viewers* since pretty much any of them will be an editor as well 957 editor_cmd = gmMimeLib.get_viewer_cmd(mimetype, self.instance_filename) 958 959 if editor_cmd is not None: 960 result = gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = True) 961 self.re_editable_filenames = [self.instance_filename] 962 963 return result964 #--------------------------------------------------------966 try: 967 post_processor = self.form_definition['form::post processor'] % self.instance_filename 968 except KeyError: 969 _log.debug('no explicit post processor defined for text template') 970 return True 971 972 self.final_output_filenames = [self.instance_filename] 973 974 return gmShellAPI.run_command_in_shell(command = post_processor, blocking = True)982 """A forms engine wrapping LaTeX.""" 9831166 #------------------------------------------------------------ 1167 form_engines[u'L'] = cLaTeXForm 1168 1169 #================================================================ 1170 # Xe(La)TeX template forms 1171 #---------------------------------------------------------------- 1172 # Xe(La)TeX: http://www.scholarsfonts.net/xetextt.pdf985 986 # create sandbox for LaTeX to play in (and don't assume 987 # much of anything about the template_file except that it 988 # is at our disposal) 989 sandbox_dir = gmTools.get_unique_filename ( 990 prefix = gmTools.fname_stem(template_file) + '_', 991 suffix = '.dir' 992 ) 993 _log.debug('LaTeX sandbox directory: [%s]', sandbox_dir) 994 gmTools.mkdir(sandbox_dir) 995 shutil.copy(template_file, sandbox_dir) 996 template_file = os.path.join(sandbox_dir, os.path.split(template_file)[1]) 997 998 super(self.__class__, self).__init__(template_file = template_file) 999 1000 self.__sandbox_dir = sandbox_dir1001 #--------------------------------------------------------1003 1004 if self.template is not None: 1005 # inject placeholder values 1006 data_source.set_placeholder(u'form_name_long', self.template['name_long']) 1007 data_source.set_placeholder(u'form_name_short', self.template['name_short']) 1008 data_source.set_placeholder(u'form_version', self.template['external_version']) 1009 1010 data_source.escape_function = gmTools.tex_escape_string 1011 data_source.escape_style = u'latex' 1012 1013 path, ext = os.path.splitext(self.template_filename) 1014 if ext in [r'', r'.']: 1015 ext = r'.tex' 1016 1017 filenames = [ 1018 self.template_filename, 1019 r'%s-result_run1%s' % (path, ext), 1020 r'%s-result_run2%s' % (path, ext), 1021 r'%s-result_run3%s' % (path, ext) 1022 ] 1023 1024 found_placeholders = True 1025 current_run = 1 1026 while found_placeholders and (current_run < 4): 1027 _log.debug('placeholder substitution run #%s', current_run) 1028 found_placeholders = self.__substitute_placeholders ( 1029 input_filename = filenames[current_run-1], 1030 output_filename = filenames[current_run], 1031 data_source = data_source 1032 ) 1033 current_run += 1 1034 1035 if self.template is not None: 1036 # remove temporary placeholders 1037 data_source.unset_placeholder(u'form_name_long') 1038 data_source.unset_placeholder(u'form_name_short') 1039 data_source.unset_placeholder(u'form_version') 1040 1041 self.instance_filename = self.re_editable_filenames[0] 1042 1043 return1044 #--------------------------------------------------------1045 - def __substitute_placeholders(self, data_source=None, input_filename=None, output_filename=None):1046 1047 _log.debug('[%s] -> [%s]', input_filename, output_filename) 1048 1049 found_placeholders = False 1050 1051 template_file = codecs.open(input_filename, 'rU', 'utf8') 1052 instance_file = codecs.open(output_filename, 'wb', 'utf8') 1053 1054 for line in template_file: 1055 1056 if line.strip() in [u'', u'\r', u'\n', u'\r\n']: # empty lines 1057 instance_file.write(line) 1058 continue 1059 if line.lstrip().startswith('%'): # TeX comment 1060 instance_file.write(line) 1061 continue 1062 1063 for placeholder_regex in [data_source.first_order_placeholder_regex, data_source.second_order_placeholder_regex, data_source.third_order_placeholder_regex]: 1064 # 1) find placeholders in this line 1065 placeholders_in_line = regex.findall(placeholder_regex, line, regex.IGNORECASE) 1066 if len(placeholders_in_line) == 0: 1067 continue 1068 _log.debug('%s placeholders found with pattern: %s', len(placeholders_in_line), placeholder_regex) 1069 found_placeholders = True 1070 # 2) replace them 1071 for placeholder in placeholders_in_line: 1072 try: 1073 val = data_source[placeholder] 1074 except: 1075 _log.exception('error with placeholder [%s]', placeholder) 1076 val = gmTools.tex_escape_string(_('error with placeholder [%s]') % placeholder) 1077 1078 if val is None: 1079 _log.debug('error with placeholder [%s]', placeholder) 1080 val = _('error with placeholder [%s]') % gmTools.tex_escape_string(placeholder) 1081 1082 line = line.replace(placeholder, val) 1083 1084 instance_file.write(line) 1085 1086 instance_file.close() 1087 self.re_editable_filenames = [output_filename] 1088 template_file.close() 1089 1090 return found_placeholders1091 #--------------------------------------------------------1093 1094 mimetypes = [ 1095 u'application/x-latex', 1096 u'application/x-tex', 1097 u'text/plain' 1098 ] 1099 1100 for mimetype in mimetypes: 1101 editor_cmd = gmMimeLib.get_editor_cmd(mimetype, self.instance_filename) 1102 if editor_cmd is not None: 1103 break 1104 1105 if editor_cmd is None: 1106 # LaTeX code is text: also consider text *viewers* 1107 # since pretty much any of them will be an editor as well 1108 for mimetype in mimetypes: 1109 editor_cmd = gmMimeLib.get_viewer_cmd(mimetype, self.instance_filename) 1110 if editor_cmd is not None: 1111 break 1112 1113 if editor_cmd is None: 1114 return False 1115 1116 result = gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = True) 1117 self.re_editable_filenames = [self.instance_filename] 1118 return result1119 #--------------------------------------------------------1121 1122 if instance_file is None: 1123 instance_file = self.instance_filename 1124 1125 try: 1126 open(instance_file, 'r').close() 1127 except: 1128 _log.exception('cannot access form instance file [%s]', instance_file) 1129 gmLog2.log_stack_trace() 1130 return None 1131 1132 self.instance_filename = instance_file 1133 1134 _log.debug('ignoring <format> directive [%s], generating PDF', format) 1135 1136 # LaTeX can need up to three runs to get cross references et al right 1137 if platform.system() == 'Windows': 1138 draft_cmd = r'pdflatex.exe -draftmode -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1139 final_cmd = r'pdflatex.exe -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1140 else: 1141 draft_cmd = r'pdflatex -draftmode -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1142 final_cmd = r'pdflatex -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1143 for run_cmd in [draft_cmd, draft_cmd, final_cmd]: 1144 if not gmShellAPI.run_command_in_shell(command = run_cmd, blocking = True, acceptable_return_codes = [0, 1]): 1145 _log.error('problem running pdflatex, cannot generate form output') 1146 gmDispatcher.send(signal = 'statustext', msg = _('Error running pdflatex. Cannot turn LaTeX template into PDF.'), beep = True) 1147 return None 1148 1149 sandboxed_pdf_name = u'%s.pdf' % os.path.splitext(self.instance_filename)[0] 1150 target_dir = os.path.normpath(os.path.join(os.path.split(sandboxed_pdf_name)[0], '..')) 1151 final_pdf_name = os.path.join ( 1152 target_dir, 1153 os.path.split(sandboxed_pdf_name)[1] 1154 ) 1155 _log.debug('copying sandboxed PDF: %s -> %s', sandboxed_pdf_name, final_pdf_name) 1156 try: 1157 shutil.copy2(sandboxed_pdf_name, target_dir) 1158 except IOError: 1159 _log.exception('cannot open/move sandboxed PDF') 1160 gmDispatcher.send(signal = 'statustext', msg = _('PDF output file cannot be opened.'), beep = True) 1161 return None 1162 1163 self.final_output_filenames = [final_pdf_name] 1164 1165 return final_pdf_name1174 """A forms engine wrapping Xe(La)TeX.""" 11751362 1363 #------------------------------------------------------------ 1364 form_engines[u'X'] = cXeTeXForm 1365 1366 #============================================================ 1367 # Gnuplot template forms 1368 #------------------------------------------------------------1177 1178 # create sandbox for LaTeX to play in (and don't assume 1179 # much of anything about the template_file except that it 1180 # is at our disposal) 1181 sandbox_dir = gmTools.get_unique_filename ( 1182 prefix = gmTools.fname_stem(template_file) + '_', 1183 suffix = '.dir' 1184 ) 1185 _log.debug('Xe(La)TeX sandbox directory: [%s]', sandbox_dir) 1186 gmTools.mkdir(sandbox_dir) 1187 shutil.copy(template_file, sandbox_dir) 1188 template_file = os.path.join(sandbox_dir, os.path.split(template_file)[1]) 1189 1190 super(self.__class__, self).__init__(template_file = template_file) 1191 1192 self.__sandbox_dir = sandbox_dir1193 #--------------------------------------------------------1195 1196 if self.template is not None: 1197 # inject placeholder values 1198 data_source.set_placeholder(u'form_name_long', self.template['name_long']) 1199 data_source.set_placeholder(u'form_name_short', self.template['name_short']) 1200 data_source.set_placeholder(u'form_version', self.template['external_version']) 1201 1202 data_source.escape_function = gmTools.xetex_escape_string 1203 data_source.escape_style = u'xetex' 1204 1205 path, ext = os.path.splitext(self.template_filename) 1206 if ext in [r'', r'.']: 1207 ext = r'.tex' 1208 1209 filenames = [ 1210 self.template_filename, 1211 r'%s-result_run1%s' % (path, ext), 1212 r'%s-result_run2%s' % (path, ext), 1213 r'%s-result_run3%s' % (path, ext) 1214 ] 1215 1216 found_placeholders = True 1217 current_run = 1 1218 while found_placeholders and (current_run < 4): 1219 _log.debug('placeholder substitution run #%s', current_run) 1220 found_placeholders = self.__substitute_placeholders ( 1221 input_filename = filenames[current_run-1], 1222 output_filename = filenames[current_run], 1223 data_source = data_source 1224 ) 1225 current_run += 1 1226 1227 if self.template is not None: 1228 # remove temporary placeholders 1229 data_source.unset_placeholder(u'form_name_long') 1230 data_source.unset_placeholder(u'form_name_short') 1231 data_source.unset_placeholder(u'form_version') 1232 1233 self.instance_filename = self.re_editable_filenames[0] 1234 1235 return1236 #--------------------------------------------------------1237 - def __substitute_placeholders(self, data_source=None, input_filename=None, output_filename=None):1238 _log.debug('[%s] -> [%s]', input_filename, output_filename) 1239 1240 found_placeholders = False 1241 1242 template_file = codecs.open(input_filename, 'rU', 'utf8') 1243 instance_file = codecs.open(output_filename, 'wb', 'utf8') 1244 1245 for line in template_file: 1246 1247 if line.strip() in [u'', u'\r', u'\n', u'\r\n']: # empty lines 1248 instance_file.write(line) 1249 continue 1250 if line.startswith('%'): # TeX comment 1251 instance_file.write(line) 1252 continue 1253 1254 for placeholder_regex in [data_source.first_order_placeholder_regex, data_source.second_order_placeholder_regex, data_source.third_order_placeholder_regex]: 1255 # 1) find placeholders in this line 1256 placeholders_in_line = regex.findall(placeholder_regex, line, regex.IGNORECASE) 1257 if len(placeholders_in_line) == 0: 1258 continue 1259 _log.debug('%s placeholders found with pattern: %s', len(placeholders_in_line), placeholder_regex) 1260 found_placeholders = True 1261 # 2) replace them 1262 for placeholder in placeholders_in_line: 1263 try: 1264 val = data_source[placeholder] 1265 except: 1266 _log.exception('error with placeholder [%s]', placeholder) 1267 val = gmTools.tex_escape_string(_('error with placeholder [%s]') % placeholder) 1268 1269 if val is None: 1270 _log.debug('error with placeholder [%s]', placeholder) 1271 val = _('error with placeholder [%s]') % gmTools.tex_escape_string(placeholder) 1272 1273 line = line.replace(placeholder, val) 1274 1275 instance_file.write(line) 1276 1277 instance_file.close() 1278 self.re_editable_filenames = [output_filename] 1279 template_file.close() 1280 1281 return found_placeholders1282 #--------------------------------------------------------1284 1285 mimetypes = [ 1286 u'application/x-xetex', 1287 u'application/x-latex', 1288 u'application/x-tex', 1289 u'text/plain' 1290 ] 1291 1292 for mimetype in mimetypes: 1293 editor_cmd = gmMimeLib.get_editor_cmd(mimetype, self.instance_filename) 1294 if editor_cmd is not None: 1295 break 1296 1297 if editor_cmd is None: 1298 # Xe(La)TeX code is utf8: also consider text *viewers* 1299 # since pretty much any of them will be an editor as well 1300 for mimetype in mimetypes: 1301 editor_cmd = gmMimeLib.get_viewer_cmd(mimetype, self.instance_filename) 1302 if editor_cmd is not None: 1303 break 1304 1305 if editor_cmd is None: 1306 return False 1307 1308 result = gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = True) 1309 self.re_editable_filenames = [self.instance_filename] 1310 return result1311 #--------------------------------------------------------1313 1314 if instance_file is None: 1315 instance_file = self.instance_filename 1316 1317 try: 1318 open(instance_file, 'r').close() 1319 except: 1320 _log.exception('cannot access form instance file [%s]', instance_file) 1321 gmLog2.log_stack_trace() 1322 return None 1323 1324 self.instance_filename = instance_file 1325 1326 _log.debug('ignoring <format> directive [%s], generating PDF', format) 1327 1328 # Xe(La)TeX can need up to three runs to get cross references et al right 1329 if platform.system() == 'Windows': 1330 # not yet supported: -draftmode 1331 # does not support: -shell-escape 1332 draft_cmd = r'xelatex.exe -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1333 final_cmd = r'xelatex.exe -interaction=nonstopmode -output-directory=%s %s' % (self.__sandbox_dir, self.instance_filename) 1334 else: 1335 # not yet supported: -draftmode 1336 draft_cmd = r'xelatex -interaction=nonstopmode -output-directory=%s -shell-escape %s' % (self.__sandbox_dir, self.instance_filename) 1337 final_cmd = r'xelatex -interaction=nonstopmode -output-directory=%s -shell-escape %s' % (self.__sandbox_dir, self.instance_filename) 1338 1339 for run_cmd in [draft_cmd, draft_cmd, final_cmd]: 1340 if not gmShellAPI.run_command_in_shell(command = run_cmd, blocking = True, acceptable_return_codes = [0, 1]): 1341 _log.error('problem running xelatex, cannot generate form output') 1342 gmDispatcher.send(signal = 'statustext', msg = _('Error running xelatex. Cannot turn Xe(La)TeX template into PDF.'), beep = True) 1343 return None 1344 1345 sandboxed_pdf_name = u'%s.pdf' % os.path.splitext(self.instance_filename)[0] 1346 target_dir = os.path.normpath(os.path.join(os.path.split(sandboxed_pdf_name)[0], '..')) 1347 final_pdf_name = os.path.join ( 1348 target_dir, 1349 os.path.split(sandboxed_pdf_name)[1] 1350 ) 1351 _log.debug('copying sandboxed PDF: %s -> %s', sandboxed_pdf_name, final_pdf_name) 1352 try: 1353 shutil.copy2(sandboxed_pdf_name, target_dir) 1354 except IOError: 1355 _log.exception('cannot open/move sandboxed PDF') 1356 gmDispatcher.send(signal = 'statustext', msg = _('PDF output file cannot be opened.'), beep = True) 1357 return None 1358 1359 self.final_output_filenames = [final_pdf_name] 1360 1361 return final_pdf_name1370 """A forms engine wrapping Gnuplot.""" 1371 1372 #-------------------------------------------------------- 1376 #--------------------------------------------------------1421 #------------------------------------------------------------ 1422 form_engines[u'G'] = cGnuplotForm 1423 1424 #============================================================ 1425 # fPDF form engine 1426 #------------------------------------------------------------1378 """Allow editing the instance of the template.""" 1379 self.re_editable_filenames = [] 1380 return True1381 #--------------------------------------------------------1383 """Generate output suitable for further processing outside this class, e.g. printing. 1384 1385 Expects .data_filename to be set. 1386 """ 1387 self.conf_filename = gmTools.get_unique_filename(prefix = 'gm2gpl-', suffix = '.conf') 1388 conf_file = codecs.open(self.conf_filename, 'wb', 'utf8') 1389 conf_file.write('# setting the gnuplot data file\n') 1390 conf_file.write("gm2gpl_datafile = '%s'\n" % self.data_filename) 1391 conf_file.close() 1392 1393 # FIXME: cater for configurable path 1394 if platform.system() == 'Windows': 1395 exec_name = 'gnuplot.exe' 1396 else: 1397 exec_name = 'gnuplot' 1398 1399 args = [exec_name, '-p', self.conf_filename, self.template_filename] 1400 _log.debug('plotting args: %s' % str(args)) 1401 1402 try: 1403 gp = subprocess.Popen ( 1404 args = args, 1405 close_fds = True 1406 ) 1407 except (OSError, ValueError, subprocess.CalledProcessError): 1408 _log.exception('there was a problem executing gnuplot') 1409 gmDispatcher.send(signal = u'statustext', msg = _('Error running gnuplot. Cannot plot data.'), beep = True) 1410 return 1411 1412 gp.communicate() 1413 1414 self.final_output_filenames = [ 1415 self.conf_filename, 1416 self.data_filename, 1417 self.template_filename 1418 ] 1419 1420 return1428 """A forms engine wrapping PDF forms. 1429 1430 Johann Felix Soden <johfel@gmx.de> helped with this. 1431 1432 http://partners.adobe.com/public/developer/en/pdf/PDFReference16.pdf 1433 1434 http://wwwimages.adobe.com/www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/fdf_data_exchange.pdf 1435 """ 14361633 #------------------------------------------------------------ 1634 form_engines[u'P'] = cPDFForm 1635 1636 #============================================================ 1637 # older code 1638 #------------------------------------------------------------1438 1439 super(cPDFForm, self).__init__(template_file = template_file) 1440 1441 # detect pdftk 1442 found, self.pdftk_binary = gmShellAPI.detect_external_binary(binary = r'pdftk') 1443 if not found: 1444 raise ImportError('<pdftk(.exe)> not found') 1445 return # should be superfluous, actually 1446 1447 enc = sys.getfilesystemencoding() 1448 self.pdftk_binary = self.pdftk_binary.encode(enc) 1449 1450 base_name, ext = os.path.splitext(self.template_filename) 1451 self.fdf_dumped_filename = (u'%s.fdf' % base_name).encode(enc) 1452 self.fdf_replaced_filename = (u'%s-replaced.fdf' % base_name).encode(enc) 1453 self.pdf_filled_filename = (u'%s-filled.pdf' % base_name).encode(enc) 1454 self.pdf_flattened_filename = (u'%s-filled-flattened.pdf' % base_name).encode(enc)1455 #--------------------------------------------------------1457 1458 # dump form fields from template 1459 cmd_line = [ 1460 self.pdftk_binary, 1461 self.template_filename, 1462 r'generate_fdf', 1463 r'output', 1464 self.fdf_dumped_filename 1465 ] 1466 _log.debug(u' '.join(cmd_line)) 1467 try: 1468 pdftk = subprocess.Popen(cmd_line) 1469 except OSError: 1470 _log.exception('cannot run <pdftk> (dump data from form)') 1471 gmDispatcher.send(signal = u'statustext', msg = _('Error running pdftk. Cannot extract fields from PDF form template.'), beep = True) 1472 return False 1473 1474 pdftk.communicate() 1475 if pdftk.returncode != 0: 1476 _log.error('<pdftk> returned [%s], failed to dump data from PDF form into FDF', pdftk.returncode) 1477 return False 1478 1479 # parse dumped FDF file for "/V (...)" records 1480 # and replace placeholders therein 1481 fdf_dumped_file = open(self.fdf_dumped_filename, 'rbU') 1482 fdf_replaced_file = codecs.open(self.fdf_replaced_filename, 'wb') 1483 1484 string_value_regex = r'\s*/V\s*\(.+\)\s*$' 1485 for line in fdf_dumped_file: 1486 if not regex.match(string_value_regex, line): 1487 fdf_replaced_file.write(line) 1488 continue 1489 1490 # strip cruft around the string value 1491 raw_str_val = line.strip() # remove framing whitespace 1492 raw_str_val = raw_str_val[2:] # remove leading "/V" 1493 raw_str_val = raw_str_val.lstrip() # remove whitespace between "/V" and "(" 1494 raw_str_val = raw_str_val[1:] # remove opening "(" 1495 raw_str_val = raw_str_val[2:] # remove BOM-16-BE 1496 raw_str_val = raw_str_val.rstrip() # remove trailing whitespace 1497 raw_str_val = raw_str_val[:-1] # remove closing ")" 1498 1499 # work on FDF escapes 1500 raw_str_val = raw_str_val.replace('\(', '(') # remove escaping of "(" 1501 raw_str_val = raw_str_val.replace('\)', ')') # remove escaping of ")" 1502 1503 # by now raw_str_val should contain the actual 1504 # string value, albeit encoded as UTF-16, so 1505 # decode it into a unicode object, 1506 # split multi-line fields on "\n" literal 1507 raw_str_lines = raw_str_val.split('\x00\\n') 1508 value_template_lines = [] 1509 for raw_str_line in raw_str_lines: 1510 value_template_lines.append(raw_str_line.decode('utf_16_be')) 1511 1512 replaced_lines = [] 1513 for value_template in value_template_lines: 1514 # find any placeholders within 1515 placeholders_in_value = regex.findall(data_source.placeholder_regex, value_template, regex.IGNORECASE) 1516 for placeholder in placeholders_in_value: 1517 try: 1518 replacement = data_source[placeholder] 1519 except: 1520 _log.exception(replacement) 1521 replacement = _('error with placeholder [%s]') % placeholder 1522 if replacement is None: 1523 replacement = _('error with placeholder [%s]') % placeholder 1524 value_template = value_template.replace(placeholder, replacement) 1525 1526 value_template = value_template.encode('utf_16_be') 1527 1528 if len(placeholders_in_value) > 0: 1529 value_template = value_template.replace(r'(', r'\(') 1530 value_template = value_template.replace(r')', r'\)') 1531 1532 replaced_lines.append(value_template) 1533 1534 replaced_line = '\x00\\n'.join(replaced_lines) 1535 1536 fdf_replaced_file.write('/V (') 1537 fdf_replaced_file.write(codecs.BOM_UTF16_BE) 1538 fdf_replaced_file.write(replaced_line) 1539 fdf_replaced_file.write(')\n') 1540 1541 fdf_replaced_file.close() 1542 fdf_dumped_file.close() 1543 1544 # merge replaced data back into form 1545 cmd_line = [ 1546 self.pdftk_binary, 1547 self.template_filename, 1548 r'fill_form', 1549 self.fdf_replaced_filename, 1550 r'output', 1551 self.pdf_filled_filename 1552 ] 1553 _log.debug(u' '.join(cmd_line)) 1554 try: 1555 pdftk = subprocess.Popen(cmd_line) 1556 except OSError: 1557 _log.exception('cannot run <pdftk> (merge data into form)') 1558 gmDispatcher.send(signal = u'statustext', msg = _('Error running pdftk. Cannot fill in PDF form template.'), beep = True) 1559 return False 1560 1561 pdftk.communicate() 1562 if pdftk.returncode != 0: 1563 _log.error('<pdftk> returned [%s], failed to merge FDF data into PDF form', pdftk.returncode) 1564 return False 1565 1566 return True1567 #--------------------------------------------------------1569 mimetypes = [ 1570 u'application/pdf', 1571 u'application/x-pdf' 1572 ] 1573 1574 for mimetype in mimetypes: 1575 editor_cmd = gmMimeLib.get_editor_cmd(mimetype, self.pdf_filled_filename) 1576 if editor_cmd is not None: 1577 break 1578 1579 if editor_cmd is None: 1580 _log.debug('editor cmd not found, trying viewer cmd') 1581 for mimetype in mimetypes: 1582 editor_cmd = gmMimeLib.get_viewer_cmd(mimetype, self.pdf_filled_filename) 1583 if editor_cmd is not None: 1584 break 1585 1586 if editor_cmd is None: 1587 return False 1588 1589 result = gmShellAPI.run_command_in_shell(command = editor_cmd, blocking = True) 1590 1591 path, fname = os.path.split(self.pdf_filled_filename) 1592 candidate = os.path.join(gmTools.gmPaths().home_dir, fname) 1593 1594 if os.access(candidate, os.R_OK): 1595 _log.debug('filled-in PDF found: %s', candidate) 1596 os.rename(self.pdf_filled_filename, self.pdf_filled_filename + '.bak') 1597 shutil.move(candidate, path) 1598 else: 1599 _log.debug('filled-in PDF not found: %s', candidate) 1600 1601 self.re_editable_filenames = [self.pdf_filled_filename] 1602 1603 return result1604 #--------------------------------------------------------1606 """Generate output suitable for further processing outside this class, e.g. printing.""" 1607 1608 # eventually flatten the filled in form so we 1609 # can keep both a flattened and an editable copy: 1610 cmd_line = [ 1611 self.pdftk_binary, 1612 self.pdf_filled_filename, 1613 r'output', 1614 self.pdf_flattened_filename, 1615 r'flatten' 1616 ] 1617 _log.debug(u' '.join(cmd_line)) 1618 try: 1619 pdftk = subprocess.Popen(cmd_line) 1620 except OSError: 1621 _log.exception('cannot run <pdftk> (flatten filled in form)') 1622 gmDispatcher.send(signal = u'statustext', msg = _('Error running pdftk. Cannot flatten filled in PDF form.'), beep = True) 1623 return None 1624 1625 pdftk.communicate() 1626 if pdftk.returncode != 0: 1627 _log.error('<pdftk> returned [%s], failed to flatten filled in PDF form', pdftk.returncode) 1628 return None 1629 1630 self.final_output_filenames = [self.pdf_flattened_filename] 1631 1632 return self.pdf_flattened_filename1640 """A forms engine wrapping LaTeX. 1641 """ 16451698 1699 1700 1701 1702 #================================================================ 1703 # define a class for HTML forms (for printing) 1704 #================================================================1647 try: 1648 latex = Cheetah.Template.Template (self.template, filter=LaTeXFilter, searchList=[params]) 1649 # create a 'sandbox' directory for LaTeX to play in 1650 self.tmp = tempfile.mktemp () 1651 os.makedirs (self.tmp) 1652 self.oldcwd = os.getcwd () 1653 os.chdir (self.tmp) 1654 stdin = os.popen ("latex", "w", 2048) 1655 stdin.write (str (latex)) #send text. LaTeX spits it's output into stdout 1656 # FIXME: send LaTeX output to the logger 1657 stdin.close () 1658 if not gmShellAPI.run_command_in_shell("dvips texput.dvi -o texput.ps", blocking=True): 1659 raise FormError ('DVIPS returned error') 1660 except EnvironmentError, e: 1661 _log.error(e.strerror) 1662 raise FormError (e.strerror) 1663 return file ("texput.ps")16641666 """ 1667 For testing purposes, runs Xdvi on the intermediate TeX output 1668 WARNING: don't try this on Windows 1669 """ 1670 gmShellAPI.run_command_in_shell("xdvi texput.dvi", blocking=True)16711673 if "%F" in command: 1674 command.replace ("%F", "texput.ps") 1675 else: 1676 command = "%s < texput.ps" % command 1677 try: 1678 if not gmShellAPI.run_command_in_shell(command, blocking=True): 1679 _log.error("external command %s returned non-zero" % command) 1680 raise FormError ('external command %s returned error' % command) 1681 except EnvironmentError, e: 1682 _log.error(e.strerror) 1683 raise FormError (e.strerror) 1684 return True16851687 command, set1 = gmCfg.getDBParam (workplace = self.workplace, option = 'main.comms.print') 1688 self.exe (command)16891706 """This class can create XML document from requested data, 1707 then process it with XSLT template and display results 1708 """ 1709 1710 # FIXME: make the path configurable ? 1711 _preview_program = u'oowriter ' #this program must be in the system PATH 17121789 1790 1791 #===================================================== 1792 #class LaTeXFilter(Cheetah.Filters.Filter):1714 1715 if template is None: 1716 raise ValueError(u'%s: cannot create form instance without a template' % __name__) 1717 1718 cFormEngine.__init__(self, template = template) 1719 1720 self._FormData = None 1721 1722 # here we know/can assume that the template was stored as a utf-8 1723 # encoded string so use that conversion to create unicode: 1724 #self._XSLTData = unicode(str(template.template_data), 'UTF-8') 1725 # but in fact, unicode() knows how to handle buffers, so simply: 1726 self._XSLTData = unicode(self.template.template_data, 'UTF-8', 'strict') 1727 1728 # we must still devise a method of extracting the SQL query: 1729 # - either by retrieving it from a particular tag in the XSLT or 1730 # - by making the stored template actually be a dict which, unpickled, 1731 # has the keys "xslt" and "sql" 1732 self._SQL_query = u'select 1' #this sql query must output valid xml1733 #-------------------------------------------------------- 1734 # external API 1735 #--------------------------------------------------------1737 """get data from backend and process it with XSLT template to produce readable output""" 1738 1739 # extract SQL (this is wrong but displays what is intended) 1740 xslt = libxml2.parseDoc(self._XSLTData) 1741 root = xslt.children 1742 for child in root: 1743 if child.type == 'element': 1744 self._SQL_query = child.content 1745 break 1746 1747 # retrieve data from backend 1748 rows, idx = gmPG2.run_ro_queries(queries = [{'cmd': self._SQL_query, 'args': sql_parameters}], get_col_idx = False) 1749 1750 __header = '<?xml version="1.0" encoding="UTF-8"?>\n' 1751 __body = rows[0][0] 1752 1753 # process XML data according to supplied XSLT, producing HTML 1754 self._XMLData =__header + __body 1755 style = libxslt.parseStylesheetDoc(xslt) 1756 xml = libxml2.parseDoc(self._XMLData) 1757 html = style.applyStylesheet(xml, None) 1758 self._FormData = html.serialize() 1759 1760 style.freeStylesheet() 1761 xml.freeDoc() 1762 html.freeDoc()1763 #--------------------------------------------------------1765 if self._FormData is None: 1766 raise ValueError, u'Preview request for empty form. Make sure the form is properly initialized and process() was performed' 1767 1768 fname = gmTools.get_unique_filename(prefix = u'gm_XSLT_form-', suffix = u'.html') 1769 #html_file = os.open(fname, 'wb') 1770 #html_file.write(self._FormData.encode('UTF-8')) 1771 html_file = codecs.open(fname, 'wb', 'utf8', 'strict') # or 'replace' ? 1772 html_file.write(self._FormData) 1773 html_file.close() 1774 1775 cmd = u'%s %s' % (self.__class__._preview_program, fname) 1776 1777 if not gmShellAPI.run_command_in_shell(command = cmd, blocking = False): 1778 _log.error('%s: cannot launch report preview program' % __name__) 1779 return False 1780 1781 #os.unlink(self.filename) #delete file 1782 #FIXME: under Windows the temp file is deleted before preview program gets it (under Linux it works OK) 1783 1784 return True1785 #--------------------------------------------------------1832 1833 1834 #=========================================================== 1837 1838 #============================================================ 1839 # convenience functions 1840 #------------------------------------------------------------1795 """ 1796 Convience function to escape ISO-Latin-1 strings for TeX output 1797 WARNING: not all ISO-Latin-1 characters are expressible in TeX 1798 FIXME: nevertheless, there are a few more we could support 1799 1800 Also intelligently convert lists and tuples into TeX-style table lines 1801 """ 1802 if type (item) is types.UnicodeType or type (item) is types.StringType: 1803 item = item.replace ("\\", "\\backslash") # I wonder about this, do we want users to be able to use raw TeX? 1804 item = item.replace ("&", "\\&") 1805 item = item.replace ("$", "\\$") 1806 item = item.replace ('"', "") # okay, that's not right, but easiest solution for now 1807 item = item.replace ("\n", "\\\\ ") 1808 if len (item.strip ()) == 0: 1809 item = "\\relax " # sometimes TeX really hates empty strings, this seems to mollify it 1810 # FIXME: cover all of ISO-Latin-1 which can be expressed in TeX 1811 if type (item) is types.UnicodeType: 1812 item = item.encode ('latin-1', 'replace') 1813 trans = {'ß':'\\ss{}', 'ä': '\\"{a}', 'Ä' :'\\"{A}', 'ö': '\\"{o}', 'Ö': '\\"{O}', 'ü': '\\"{u}', 'Ü': '\\"{U}', 1814 '\x8a':'\\v{S}', '\x8a':'\\OE{}', '\x9a':'\\v{s}', '\x9c': '\\oe{}', '\a9f':'\\"{Y}', #Microsloth extensions 1815 '\x86': '{\\dag}', '\x87': '{\\ddag}', '\xa7':'{\\S}', '\xb6': '{\\P}', '\xa9': '{\\copyright}', '\xbf': '?`', 1816 '\xc0':'\\`{A}', '\xa1': "\\'{A}", '\xa2': '\\^{A}', '\xa3':'\\~{A}', '\\xc5': '{\AA}', 1817 '\xc7':'\\c{C}', '\xc8':'\\`{E}', 1818 '\xa1': '!`', 1819 '\xb5':'$\mu$', '\xa3': '\pounds{}', '\xa2':'cent'} 1820 for k, i in trans.items (): 1821 item = item.replace (k, i) 1822 elif type (item) is types.ListType or type (item) is types.TupleType: 1823 item = string.join ([self.filter (i, ' & ') for i in item], table_sep) 1824 elif item is None: 1825 item = '\\relax % Python None\n' 1826 elif type (item) is types.IntType or type (item) is types.FloatType: 1827 item = str (item) 1828 else: 1829 item = str (item) 1830 _log.warning("unknown type %s, string %s" % (type (item), item)) 1831 return item1842 """ 1843 Instantiates a FormEngine based on the form ID or name from the backend 1844 """ 1845 try: 1846 # it's a number: match to form ID 1847 id = int (id) 1848 cmd = 'select template, engine, pk from paperwork_templates where pk = %s' 1849 except ValueError: 1850 # it's a string, match to the form's name 1851 # FIXME: can we somehow OR like this: where name_short=%s OR name_long=%s ? 1852 cmd = 'select template, engine, flags, pk from paperwork_templates where name_short = %s' 1853 result = gmPG.run_ro_query ('reference', cmd, None, id) 1854 if result is None: 1855 _log.error('error getting form [%s]' % id) 1856 raise gmExceptions.FormError ('error getting form [%s]' % id) 1857 if len(result) == 0: 1858 _log.error('no form [%s] found' % id) 1859 raise gmExceptions.FormError ('no such form found [%s]' % id) 1860 if result[0][1] == 'L': 1861 return LaTeXForm (result[0][2], result[0][0]) 1862 elif result[0][1] == 'T': 1863 return TextForm (result[0][2], result[0][0]) 1864 else: 1865 _log.error('no form engine [%s] for form [%s]' % (result[0][1], id)) 1866 raise FormError ('no engine [%s] for form [%s]' % (result[0][1], id))1867 #------------------------------------------------------------- 1874 #------------------------------------------------------------- 1875 1876 test_letter = """ 1877 \\documentclass{letter} 1878 \\address{ $DOCTOR \\\\ 1879 $DOCTORADDRESS} 1880 \\signature{$DOCTOR} 1881 1882 \\begin{document} 1883 \\begin{letter}{$RECIPIENTNAME \\\\ 1884 $RECIPIENTADDRESS} 1885 1886 \\opening{Dear $RECIPIENTNAME} 1887 1888 \\textbf{Re:} $PATIENTNAME, DOB: $DOB, $PATIENTADDRESS \\\\ 1889 1890 $TEXT 1891 1892 \\ifnum$INCLUDEMEDS>0 1893 \\textbf{Medications List} 1894 1895 \\begin{tabular}{lll} 1896 $MEDSLIST 1897 \\end{tabular} 1898 \\fi 1899 1900 \\ifnum$INCLUDEDISEASES>0 1901 \\textbf{Disease List} 1902 1903 \\begin{tabular}{l} 1904 $DISEASELIST 1905 \\end{tabular} 1906 \\fi 1907 1908 \\closing{$CLOSING} 1909 1910 \\end{letter} 1911 \\end{document} 1912 """ 1913 19141916 f = open('../../test-area/ian/terry-form.tex') 1917 params = { 1918 'RECIPIENT': "Dr. R. Terry\n1 Main St\nNewcastle", 1919 'DOCTORSNAME': 'Ian Haywood', 1920 'DOCTORSADDRESS': '1 Smith St\nMelbourne', 1921 'PATIENTNAME':'Joe Bloggs', 1922 'PATIENTADDRESS':'18 Fred St\nMelbourne', 1923 'REQUEST':'echocardiogram', 1924 'THERAPY':'on warfarin', 1925 'CLINICALNOTES':"""heard new murmur 1926 Here's some 1927 crap to demonstrate how it can cover multiple lines.""", 1928 'COPYADDRESS':'Karsten Hilbert\nLeipzig, Germany', 1929 'ROUTINE':1, 1930 'URGENT':0, 1931 'FAX':1, 1932 'PHONE':1, 1933 'PENSIONER':1, 1934 'VETERAN':0, 1935 'PADS':0, 1936 'INSTRUCTIONS':u'Take the blue pill, Neo' 1937 } 1938 form = LaTeXForm (1, f.read()) 1939 form.process (params) 1940 form.xdvi () 1941 form.cleanup ()19421944 form = LaTeXForm (2, test_letter) 1945 params = {'RECIPIENTNAME':'Dr. Richard Terry', 1946 'RECIPIENTADDRESS':'1 Main St\nNewcastle', 1947 'DOCTOR':'Dr. Ian Haywood', 1948 'DOCTORADDRESS':'1 Smith St\nMelbourne', 1949 'PATIENTNAME':'Joe Bloggs', 1950 'PATIENTADDRESS':'18 Fred St, Melbourne', 1951 'TEXT':"""This is the main text of the referral letter""", 1952 'DOB':'12/3/65', 1953 'INCLUDEMEDS':1, 1954 'MEDSLIST':[["Amoxycillin", "500mg", "TDS"], ["Perindopril", "4mg", "OD"]], 1955 'INCLUDEDISEASES':0, 'DISEASELIST':'', 1956 'CLOSING':'Yours sincerely,' 1957 } 1958 form.process (params) 1959 print os.getcwd () 1960 form.xdvi () 1961 form.cleanup ()1962 #------------------------------------------------------------1964 template = open('../../test-area/ian/Formularkopf-DE.tex') 1965 form = LaTeXForm(template=template.read()) 1966 params = { 1967 'PATIENT LASTNAME': 'Kirk', 1968 'PATIENT FIRSTNAME': 'James T.', 1969 'PATIENT STREET': 'Hauptstrasse', 1970 'PATIENT ZIP': '02999', 1971 'PATIENT TOWN': 'Gross Saerchen', 1972 'PATIENT DOB': '22.03.1931' 1973 } 1974 form.process(params) 1975 form.xdvi() 1976 form.cleanup()1977 1978 #============================================================ 1979 # main 1980 #------------------------------------------------------------ 1981 if __name__ == '__main__': 1982 1983 if len(sys.argv) < 2: 1984 sys.exit() 1985 1986 if sys.argv[1] != 'test': 1987 sys.exit() 1988 1989 from Gnumed.pycommon import gmDateTime 1990 gmDateTime.init() 1991 1992 #-------------------------------------------------------- 1993 # OOo 1994 #--------------------------------------------------------1996 init_ooo()1997 #-------------------------------------------------------- 2002 #--------------------------------------------------------2004 srv = gmOOoConnector() 2005 doc = srv.open_document(filename = sys.argv[2]) 2006 print "document:", doc2007 #--------------------------------------------------------2009 doc = cOOoLetter(template_file = sys.argv[2]) 2010 doc.open_in_ooo() 2011 print "document:", doc 2012 raw_input('press <ENTER> to continue') 2013 doc.show() 2014 #doc.replace_placeholders() 2015 #doc.save_in_ooo('~/test_cOOoLetter.odt') 2016 # doc = None 2017 # doc.close_in_ooo() 2018 raw_input('press <ENTER> to continue')2019 #--------------------------------------------------------2021 try: 2022 doc = open_uri_in_ooo(filename=sys.argv[1]) 2023 except: 2024 _log.exception('cannot open [%s] in OOo' % sys.argv[1]) 2025 raise 2026 2027 class myCloseListener(unohelper.Base, oooXCloseListener): 2028 def disposing(self, evt): 2029 print "disposing:"2030 def notifyClosing(self, evt): 2031 print "notifyClosing:" 2032 def queryClosing(self, evt, owner): 2033 # owner is True/False whether I am the owner of the doc 2034 print "queryClosing:" 2035 2036 l = myCloseListener() 2037 doc.addCloseListener(l) 2038 2039 tfs = doc.getTextFields().createEnumeration() 2040 print tfs 2041 print dir(tfs) 2042 while tfs.hasMoreElements(): 2043 tf = tfs.nextElement() 2044 if tf.supportsService('com.sun.star.text.TextField.JumpEdit'): 2045 print tf.getPropertyValue('PlaceHolder') 2046 print " ", tf.getPropertyValue('Hint') 2047 2048 # doc.close(True) # closes but leaves open the dedicated OOo window 2049 doc.dispose() # closes and disposes of the OOo window 2050 #--------------------------------------------------------2052 pat = gmPersonSearch.ask_for_patient() 2053 if pat is None: 2054 return 2055 gmPerson.set_active_patient(patient = pat) 2056 2057 doc = cOOoLetter(template_file = sys.argv[2]) 2058 doc.open_in_ooo() 2059 print doc 2060 doc.show() 2061 #doc.replace_placeholders() 2062 #doc.save_in_ooo('~/test_cOOoLetter.odt') 2063 doc = None 2064 # doc.close_in_ooo() 2065 raw_input('press <ENTER> to continue')2066 #-------------------------------------------------------- 2067 # other 2068 #--------------------------------------------------------2070 template = cFormTemplate(aPK_obj = sys.argv[2]) 2071 print template 2072 print template.export_to_file()2073 #--------------------------------------------------------2075 template = cFormTemplate(aPK_obj = sys.argv[2]) 2076 template.update_template_from_file(filename = sys.argv[3])2077 #--------------------------------------------------------2079 pat = gmPersonSearch.ask_for_patient() 2080 if pat is None: 2081 return 2082 gmPerson.set_active_patient(patient = pat) 2083 2084 gmStaff.gmCurrentProvider(provider = gmStaff.cStaff()) 2085 2086 path = os.path.abspath(sys.argv[2]) 2087 form = cLaTeXForm(template_file = path) 2088 2089 from Gnumed.wxpython import gmMacro 2090 ph = gmMacro.gmPlaceholderHandler() 2091 ph.debug = True 2092 instance_file = form.substitute_placeholders(data_source = ph) 2093 pdf_name = form.generate_output(instance_file = instance_file) 2094 print "final PDF file is:", pdf_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 = cPDFForm(template_file = path) 2106 2107 from Gnumed.wxpython import gmMacro 2108 ph = gmMacro.gmPlaceholderHandler() 2109 ph.debug = True 2110 instance_file = form.substitute_placeholders(data_source = ph) 2111 pdf_name = form.generate_output(instance_file = instance_file) 2112 print "final PDF file is:", pdf_name2113 #--------------------------------------------------------2115 pat = gmPersonSearch.ask_for_patient() 2116 if pat is None: 2117 return 2118 gmPerson.set_active_patient(patient = pat) 2119 2120 gmStaff.gmCurrentProvider(provider = gmStaff.cStaff()) 2121 2122 path = os.path.abspath(sys.argv[2]) 2123 form = cAbiWordForm(template_file = path) 2124 2125 from Gnumed.wxpython import gmMacro 2126 ph = gmMacro.gmPlaceholderHandler() 2127 ph.debug = True 2128 instance_file = form.substitute_placeholders(data_source = ph) 2129 form.edit() 2130 final_name = form.generate_output(instance_file = instance_file) 2131 print "final file is:", final_name2132 #--------------------------------------------------------2134 pat = gmPersonSearch.ask_for_patient() 2135 if pat is None: 2136 return 2137 gmPerson.set_active_patient(patient = pat) 2138 2139 gmStaff.gmCurrentProvider(provider = gmStaff.cStaff()) 2140 2141 path = os.path.abspath(sys.argv[2]) 2142 form = cTextForm(template_file = path) 2143 2144 from Gnumed.wxpython import gmMacro 2145 ph = gmMacro.gmPlaceholderHandler() 2146 ph.debug = True 2147 print "placeholder substitution worked:", form.substitute_placeholders(data_source = ph) 2148 form.edit() 2149 form.generate_output()2150 #-------------------------------------------------------- 2151 #-------------------------------------------------------- 2152 #-------------------------------------------------------- 2153 # now run the tests 2154 #test_au() 2155 #test_de() 2156 2157 # OOo 2158 #test_init_ooo() 2159 #test_ooo_connect() 2160 #test_open_ooo_doc_from_srv() 2161 #test_open_ooo_doc_from_letter() 2162 #play_with_ooo() 2163 #test_cOOoLetter() 2164 2165 #test_cFormTemplate() 2166 #set_template_from_file() 2167 test_latex_form() 2168 #test_pdf_form() 2169 #test_abiword_form() 2170 #test_text_form() 2171 2172 #============================================================ 2173
Home | Trees | Indices | Help |
|
---|
Generated by Epydoc 3.0.1 on Sat Oct 5 03:56:45 2013 | http://epydoc.sourceforge.net |