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