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