Package Gnumed :: Package wxpython :: Module gmFormPrinter |
[frames] | no frames]

# Source Code for Module Gnumed.wxpython.gmFormPrinter

      1  # GNUmed form printer design study
      2
      3  __doc__ = """
      4  Module to print a form using the wx. toolkit.
      5  includes dialogues for printer calibration, etc.
      6  and new form wizard.
      7  """
      8  # $Source: /home/ncq/Projekte/cvs2git/vcs-mirror/gnumed/gnumed/client/wxpython/gmFormPrinter.py,v $
      9  # $Id: gmFormPrinter.py,v 1.12 2009-01-15 11:35:41 ncq Exp $
     10  __version__ = "$Revision: 1.12 $"
     11  __author__ = "Ian Haywood"
     12
     13  try:
     14          import wxversion
     15          import wx
     16  except ImportError:
     17          from wxPython import wx
     18
     19  import string
     20
     21  from Gnumed.pycommon import gmCfg, gmI18N
     22
     23  try:
     24          _('dummy-no-need-to-translate-but-make-epydoc-happy')
     25  except NameError:
     26          _ = lambda x:x
     27
     28  cache_form = 0 # cached variables to allow repeat of last form
     29  cache_params = {}
     30
     31  SCRIPT = -100 # fake form ID that maps to the default prescription form
     32                # for this locale
     33  PATH = -101
     34  RADIOL = -102
     35
     36 -class FormPrinter:
     37
     38 -    def __init__ (self):
     39          self._cfg = gmCfg.gmDefCfgFile
     40          xos = self._cfg.get ("printer", "x_offset")
     41          if xos is None:
     42              self.printer_unset = 1
     43              gpsd = gmPrinterSetupDialog (self)
     44          else:
     45              self.printer_unset = 0
     46              self.x_off = float (xos) # in mm from paper-edge
     47              self.y_off = float (self._cfg.get ("printer", "y_offset")) # in mm from paper-edge
     48              self.x_scale = float (self._cfg.get ("printer", "x_scaling")) # no. of logical units = 1mm
     49              self.y_scale = float (self._cfg.get ("printer", "y_scaling")) # no. logical units  = 1mm
     50          self._log = gmLog.gmDefLog.Log
     51
     52 -    def save (self):
     53          self._cfg.set ("printer", "x_offset", self.x_off)
     54          self._cfg.set ("printer", "y_offset", self.y_off)
     55          self._cfg.set ("printer", "x_scaling", self.x_scale)
     56          self._cfg.set ("printer", "y_scaling", self.x_scale)
     57          self._cfg.store ()
     58
     59 -    def printform (id, param):
     60          """
     61          Print a form. id is the database ID of the form, params is a dictionary of
     62          parameters, defined by the type of form (see gmoffice.sql)
     63          """
     64          cached_form = id
     65          cached_params = param
     66          if self.printer_unset: # printer is unset, cache and return
     67              return
     68          backend = gmPG.GetConnectionPool ()
     69          db = backend.GetConnection('office')
     70          curs = db.cursor()
     71          if id == SCRIPT:
     72              curs.execute ("select length, width, fontsize from forms, papersizes where id_papersize = papersizes.id and forms.type = 's' and default")
     73          elif id == PATH:
     74              curs.execute ("select length, width, fontsize from forms, papersizes where id_papersize = papersizes.id and forms.type = 'p' and default")
     75          elif id == RADIOL:
     76              curs.execute ("select length, width, fontsize from forms, papersizes where id_papersize = papersizes.id and forms.type = 'r' and default")
     77          else:
     78              curs.execute('select length, width, fontsize from forms, papersizes where id = %s and id_papersize = papersizes.id' % id)
     79          p_len, p_wid, fontsize, font = curs.fetchone()
     80          curs.execute('select x, y, wraparound, service, query, page from formfield, queries where id_form = %s and id_query = query.id order by page' % id)
     81          curr_page = 1
     82          # magic to set up Printer DC
     83          pd = wxPrintData ()
     84          if wxPlatform == '__WXMSW__':
     85              dc = wxPrinterDC (pd)
     86          else:
     87              # use PostScript
     88              # FIXME: how do we print under Mac??
     89              dc = wxPostScriptDC (pd)
     90          font = wx.Font (fontsize, wxDEFAULT, wx.NORMAL, wx.NORMAL)
     91          dc.SetFont (font)
     92          dc.SetBrush (wx.BLACK_BRUSH)
     93          dc.StartDoc ("")
     94          dc.StartPage ()
     95          for (x, y, wraparound, service, query, page) in curs.fetchall ():
     96              qdb = backend.GetConnection (service)
     97              qcurs = qdb.cursor ()
     98              qcurs.execute (self.subst_param (query, params))
     99              if page <> curr_page:
    100                  # new page
    101                  dc.EndPage ()
    102                  dc.StartPage ()
    103                  curr_page = page
    104              for row in qcurs.fetchall ():
    105                  text = string.join ([str(i) for i in row], ' ')
    106                  for line in string.split (text, '\n'): # honour \n in string
    107                      y = self.printtext (dc, x, y, wraparound, line)
    108              qcurs.close ()
    109              backend.ReleaseConnection (service)
    110          curs.close()
    111          dc.EndPage ()
    112          dc.EndDoc ()
    113          del dc
    114
    115
    116          def subst_param (query, param):
    117              for (name, value) in param.items ():
    118                  query = replace (query, '$' + name, value)
    119
    120          def printtext (dc, x, y, wrap, text):
    121              """
    122              Prints text, with word wrapping.
    123              Returns where it leaves y (the next virtual line)
    124              """
    125              w, h = dc.GetTextExtent (text)
    126              nextline = ""
    127              while w/float (self.x_scale) > wrap: # text is too wide
    128                  text.strip ()
    129                  # nibble from the end of text and add to nextline
    130                  # until we encounter whitespace
    131                  # re-calculate text width
    132                  pos = string.rfind (text, ' ') # returns -1 if cannot find
    133                  nextline = text[pos:] + nextline
    134                  text = text[:pos]
    135                  w, h = dc.GetTextExtent (text)
    136              px = (x+self.x_off)*self.x_scale
    137              py = (y+self.y_off)*self.y_scale
    138              dc.DrawText (px, py, text)
    139              y += (h/float (self.y_scale))*1.2 # advance one line, give 20% space
    140              # do the wrapped line if neccessary
    141              if len (nextline) > 0:
    142                  y = self.printtext (dc, x, y, wrap, nextline)
    143              # return new y position
    144              return y
    145
    146 -class gmPrinterSetupDialog (wx.Dialog):
    147 -    def __init__(self, formprinter):
    148          # begin wxGlade: __init__
    149          wx.Dialog.__init__(self, None, -1, _("Printer Setup"))
    150          self.formprinter = formprinter
    151          self.label_1 = wx.StaticText(self, -1, "Horiz. Offset")
    152          self.horiz_off_spin = wx.SpinCtrl(self, -1, min=0, max=100, initial=0)
    153          self.label_2 = wx.StaticText(self, -1, "Vert. Offset")
    154          self.vert_off_spin = wx.SpinCtrl(self, -1, min=0, max=100, initial=0, style=wx.SP_ARROW_KEYS)
    155          self.label_3 = wx.StaticText(self, -1, "Horiz. Scaling")
    156          self.horiz_scale_spin = wx.SpinCtrl(self, -1, min=0, max=100, initial=0, style=wx.SP_ARROW_KEYS)
    157          self.label_4 = wx.StaticText(self, -1, "Vert. Scaling")
    158          self.vert_scale_spin = wx.SpinCtrl(self, -1, min=0, max=100, initial=0)
    159          REPRINT_ID = wx.NewId ()
    160          self.reprint_button = wx.Button(self, REPRINT_ID, "Re-print")
    161          CALIB_ID = wx.NewId ()
    162          self.calib_button = wx.Button(self, CALIB_ID, "Re-calibrate")
    163          DISMISS_ID = wx.NewId ()
    164          self.dismiss_button = wx.Button(self, DISMISS_ID, "Dismiss")
    165          self.text_ctrl_1 = wxTextCtrl(self, -1, "You need to enter parameters so forms print properly on this printer", style=wx.TE_MULTILINE|wx.TE_READONLY)
    166
    167          self.__set_properties()
    168          self.__do_layout()
    169          # end wxGlade
    170          if not self.formprinter.printer_unset:
    171              self.horiz_off_spin.SetValue (self.formprinter.x_off)
    172              self.vert_off_spin.SetValue (self.formprinter.y_off)
    173              self.horiz_scale_spin.SetValue (self.formprinter.x_scale)
    174              self.vert_scale_spin.SetValue (self.formprinter.y_scale)
    175          else:
    176              self.horiz_off_spin.SetValue (0)
    177              self.horiz_scale_spin.SetValue (28.3)
    178              self.vert_off_spin.SetValue (0) # this is a sensible value on UNIX
    179              self.vert_scale_spin.SetValue (28.3)
    180          wx.EVT_BUTTON (self, REPRINT_ID, self.OnReprint)
    181          wx.EVT_BUTTON (self, CALIB_ID, self.OnRecalibrate)
    182          wx.EVT_BUTTON (self, DISMISS_ID, self.OnDismiss)
    183          self.Show ()
    184
    185 -    def OnDismiss (self, event):
    186          # load spins back into form engine
    187          self.formprinter.x_off = self.horiz_off_spin.GetValue ()
    188          self.formprinter.y_off = self.vert_off_spin.GetValue ()
    189          self.formprinter.x_scale = self.horiz_scale_spin.GetValue ()
    190          self.formprinter.y_scale = self.vert_scale_spin.GetValue ()
    191          self.formprinter.save ()
    192          self.Destroy ()
    193
    194 -    def OnReprint (self, event):
    195          # load spins back into form engine
    196          self.formprinter.x_off = self.horiz_off_spin.GetValue ()
    197          self.formprinter.y_off = self.vert_off_spin.GetValue ()
    198          self.formprinter.x_scale = self.horiz_scale_spin.GetValue ()
    199          self.formprinter.y_scale = self.vert_scale_spin.GetValue ()
    200          self.formprinter.printer_unset = 0
    201          if cache_form != 0:
    202              self.formprinter.printform (cache_form, cache_params)
    203
    204 -    def OnRecalibrate (self, event):
    205          dialog = gmCalibrationDialog ()
    206          pd = wxPrintData ()
    207          pd.SetPrinterCommand ("lpr")
    208          if wxPlatform == '__WXMSW__':
    209              dc = wxPrinterDC (pd)
    210          else:
    211              dc = wxPostScriptDC (pd)
    212          dc.StartDoc ("")
    213          dc.StartPage ()
    214          dc.SetBrush (wx.BLACK_BRUSH)
    215          dc.DrawRectangle (1000, 1000, 200, 200)
    216          dc.DrawRectangle (2000, 2000, 200, 200)
    217          dc.EndPage ()
    218          dc.EndDoc ()
    219          del dc
    220          dialog.ShowModal ()
    221          x1, y1, x2, y2 = dialog.GetValues ()
    222          dialog.Destroy ()
    223          self.formprinter.x_scale = (x2-x1)/1000.0
    224          self.formprinter.y_scale = (y2-y1)/1000.0
    225          self.formprinter.x_off = x1-(x2-x1)
    226          self.formprinter.y_off = y1-(y2-y1)
    227          self.formprinter.printer_unset = 0
    228          self.horiz_off_spin.SetValue (self.formprinter.x_off)
    229          self.vert_off_spin.SetValue (self.formprinter.y_off)
    230          self.horiz_scale_spin.SetValue (self.formprinter.x_scale)
    231          self.vert_scale_spin.SetValue (self.formprinter.y_scale)
    232          self.formprinter.save ()
    233
    234 -    def __set_properties(self):
    235          # begin wxGlade: __set_properties
    236          self.SetTitle("Setup Printer for Forms")
    237          self.vert_off_spin.SetToolTipString("Move text down (in millimetres)")
    238          self.horiz_scale_spin.SetToolTipString("Horizontal scaling (units per mm)")
    239          self.vert_scale_spin.SetToolTipString("Vertical scaling (units per mm)")
    240          self.reprint_button.SetToolTipString("Re-print the last printed form")
    241          self.calib_button.SetToolTipString("Print a table to calibrate this printer")
    242          self.dismiss_button.SetToolTipString("Dismiss this dialog box")
    243          # end wxGlade
    244
    245 -    def __do_layout(self):
    246          # begin wxGlade: __do_layout
    247          sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
    248          sizer_2 = wx.BoxSizer(wx.VERTICAL)
    249          sizer_3 = wx.BoxSizer(wx.VERTICAL)
    250          sizer_7 = wx.BoxSizer(wx.HORIZONTAL)
    251          sizer_6 = wx.BoxSizer(wx.HORIZONTAL)
    252          sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
    253          sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
    254          sizer_4.Add(self.label_1, 0, wx.ALL, 10)
    255          sizer_4.Add(self.horiz_off_spin, 0, wx.ALL, 10)
    256          sizer_3.Add(sizer_4, 1, wx.EXPAND, 0)
    257          sizer_5.Add(self.label_2, 0, wx.ALL, 10)
    258          sizer_5.Add(self.vert_off_spin, 0, wx.ALL, 10)
    259          sizer_3.Add(sizer_5, 1, wx.EXPAND, 0)
    260          sizer_6.Add(self.label_3, 0, wx.ALL, 10)
    261          sizer_6.Add(self.horiz_scale_spin, 0, wx.ALL, 10)
    262          sizer_3.Add(sizer_6, 1, wx.EXPAND, 0)
    263          sizer_7.Add(self.label_4, 0, wx.ALL, 10)
    264          sizer_7.Add(self.vert_scale_spin, 0, wx.ALL, 10)
    265          sizer_3.Add(sizer_7, 1, wx.EXPAND, 0)
    266          sizer_1.Add(sizer_3, 1, wx.EXPAND, 0)
    267          sizer_2.Add(self.reprint_button, 0, wx.ALL|wx.EXPAND, 10)
    268          sizer_2.Add(self.calib_button, 0, wx.ALL|wx.EXPAND, 10)
    269          sizer_2.Add(self.dismiss_button, 0, wx.ALL|wx.EXPAND, 10)
    270          sizer_2.Add(self.text_ctrl_1, 1, wx.EXPAND, 0)
    271          sizer_1.Add(sizer_2, 1, wxALL|wx.EXPAND|wx.ALIGN_RIGHT, 30)
    272          self.SetAutoLayout(1)
    273          self.SetSizer(sizer_1)
    274          sizer_1.Fit(self)
    275          self.Layout()
    276          # end wxGlade
    277
    278  # end of class Printer
    279
    280 -class gmCalibrationDialog(wx.Dialog):
    281 -    def __init__(self):
    282          # begin wxGlade: __init__
    283          #kwds["style"] = wxDIALOG_MODAL|wxCAPTION
    284          wx.Dialog.__init__(self, None, -1, _("Calibration"))
    285          self.label_9 = wx.StaticText(self, -1, """Calibration Page now printing.\n
    286  Measure the position of the boxes and enter""")
    287          self.label_5 = wx.StaticText(self, -1, "Distance of first box from top of page")
    288          self.first_top_spin = wx.SpinCtrl(self, -1, min=0, max=100, initial=0)
    289          self.label_6 = wx.StaticText(self, -1, "Distance of first box from left of page")
    290          self.first_left_spin = wx.SpinCtrl(self, -1, min=0, max=100, initial=0)
    291          self.label_7 = wx.StaticText(self, -1, "Distance of second box of top of page")
    292          self.sec_top_spin = wx.SpinCtrl(self, -1, min=0, max=100, initial=0)
    293          self.label_8 = wx.StaticText(self, -1, "Distance of second box from left of page")
    294          self.sec_left_spin = wx.SpinCtrl(self, -1, min=0, max=100, initial=0)
    295          ID = wx.NewId ()
    296          self.ok_button = wx.Button(self, ID, "OK")
    297          wx.EVT_BUTTON (self, ID, self.OnOK)
    298          self.__set_properties()
    299          self.__do_layout()
    300          # end wxGlade
    301          self.Show ()
    302
    303 -    def __set_properties(self):
    304          # begin wxGlade: __set_properties
    305          self.SetTitle("Calibration")
    306          # end wxGlade
    307
    308 -    def __do_layout(self):
    309          # begin wxGlade: __do_layout
    310          sizer_8 = wx.BoxSizer(wx.VERTICAL)
    311          grid_sizer_2 = wx.FlexGridSizer(4, 2, 0, 0)
    312          sizer_8.Add(self.label_9, 0, wx.ALL|wx.EXPAND, 10)
    313          grid_sizer_2.Add(self.label_5, 0, 0, 0)
    314          grid_sizer_2.Add(self.first_top_spin, 0, 0, 0)
    315          grid_sizer_2.Add(self.label_6, 0, 0, 0)
    316          grid_sizer_2.Add(self.first_left_spin, 0, 0, 0)
    317          grid_sizer_2.Add(self.label_7, 0, 0, 0)
    318          grid_sizer_2.Add(self.sec_top_spin, 0, 0, 0)
    319          grid_sizer_2.Add(self.label_8, 0, 0, 0)
    320          grid_sizer_2.Add(self.sec_left_spin, 0, 0, 0)
    321          grid_sizer_2.AddGrowableRow(0)
    322          grid_sizer_2.AddGrowableRow(1)
    323          grid_sizer_2.AddGrowableRow(2)
    324          grid_sizer_2.AddGrowableRow(3)
    325          grid_sizer_2.AddGrowableCol(0)
    326          sizer_8.Add(grid_sizer_2, 1, wx.EXPAND, 0)
    327          sizer_8.Add(self.ok_button, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 10)
    328          self.SetAutoLayout(1)
    329          self.SetSizer(sizer_8)
    330          sizer_8.Fit(self)
    331          self.Layout()
    332          # end wxGlade
    333
    334 -    def OnOK (self, event):
    335          self.Hide ()
    336
    337 -    def GetValues (self):
    338          return (self.first_top_spin.GetValue (),
    339                  self.first_left_spin.GetValue (),
    340                  self.sec_top_spin.GetValue (),
    341                  self.sec_left_spin.GetValue ())
    342
    343  # end of class gmCalibrationDialog
    344
    345  fp = FormPrinter ()
    346  psd = gmPrinterSetupDialog (fp)
    347
    348  #=================================================
    349