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