Package Gnumed :: Package wxpython :: Package gui :: Module gmXdtViewer |
[frames] | no frames]

# Source Code for Module Gnumed.wxpython.gui.gmXdtViewer

      1  # -*- coding: utf-8 -*-
      2  """GNUmed xDT viewer.
      3
      4  TODO:
      5
      6  - popup menu on right-click
      7    - import this line
      8    - import all lines like this
      9    - search
     10    - print
     11    - ...
     12  """
     13  #=============================================================================
     14  __author__ = "S.Hilbert, K.Hilbert"
     15
     16  import sys, os, os.path, io, logging
     17
     18
     19  import wx
     20
     21
     22  from Gnumed.wxpython import gmGuiHelpers, gmPlugin
     23  from Gnumed.pycommon import gmI18N, gmDispatcher
     24  from Gnumed.business import gmXdtMappings, gmXdtObjects
     25  from Gnumed.wxGladeWidgets import wxgXdtListPnl
     26  from Gnumed.wxpython import gmAccessPermissionWidgets
     27
     28
     29  _log = logging.getLogger('gm.ui')
     30
     31  #=============================================================================
     32  # FIXME: this belongs elsewhere under wxpython/
     33 -class cXdtListPnl(wxgXdtListPnl.wxgXdtListPnl):
     34 -        def __init__(self, *args, **kwargs):
     35                  wxgXdtListPnl.wxgXdtListPnl.__init__(self, *args, **kwargs)
     36
     37                  self.filename = None
     38
     39                  self.__cols = [
     40                          _('Field name'),
     41                          _('Interpreted content'),
     42                          _('xDT field ID'),
     43                          _('Raw content')
     44                  ]
     45                  self.__init_ui()
     46          #--------------------------------------------------------------
     47 -        def __init_ui(self):
     48                  for col in range(len(self.__cols)):
     49                          self._LCTRL_xdt.InsertColumn(col, self.__cols[col])
     50          #--------------------------------------------------------------
     51          # external API
     52          #--------------------------------------------------------------
     53 -        def select_file(self, path=None):
     54                  if path is None:
     55                          root_dir = os.path.expanduser(os.path.join('~', 'gnumed'))
     56                  else:
     57                          root_dir = path
     58                  # get file name
     59                  # - via file select dialog
     60                  dlg = wx.FileDialog (
     61                          parent = self,
     62                          message = _("Choose an xDT file"),
     63                          defaultDir = root_dir,
     64                          defaultFile = '',
     65                          wildcard = '%s (*.xDT)|*.?DT;*.?dt|%s (*)|*|%s (*.*)|*.*' % (_('xDT files'), _('all files'), _('all files (Win)')),
     66                          style = wx.FD_OPEN | wx.FD_FILE_MUST_EXIST
     67                  )
     68                  choice = dlg.ShowModal()
     69                  fname = None
     70                  if choice == wx.ID_OK:
     71                          fname =  dlg.GetPath()
     72                  dlg.DestroyLater()
     73                  return fname
     74          #--------------------------------------------------------------
     75 -        def load_file(self, filename=None):
     76                  if filename is None:
     77                          filename = self.select_file()
     78                  if filename is None:
     79                          return True
     80
     81                  self.filename = None
     82
     83                  try:
     84                          f = open(filename, 'r')
     85                  except IOError:
     86                          gmGuiHelpers.gm_show_error (
     87                                  _('Cannot access xDT file\n\n'
     88                                    ' [%s]'),
     89                                  _('loading xDT file')
     90                          )
     91                          return False
     92                  f.close()
     93
     94                  encoding = gmXdtObjects.determine_xdt_encoding(filename = filename)
     95                  if encoding is None:
     96                          encoding = 'utf8'
     97                          gmDispatcher.send(signal = 'statustext', msg = _('Encoding missing in xDT file. Assuming [%s].') % encoding)
     98                          _log.warning('xDT file [%s] does not define an encoding, assuming [%s]' % (filename, encoding))
     99
    100                  try:
    101                          xdt_file = io.open(filename, mode = 'rt', encoding = encoding, errors = 'replace')
    102                  except IOError:
    103                          gmGuiHelpers.gm_show_error (
    104                                  _('Cannot access xDT file\n\n'
    105                                    ' [%s]'),
    106                                  _('loading xDT file')
    107                          )
    108                          return False
    109
    110                  # parse and display file
    111                  self._LCTRL_xdt.DeleteAllItems()
    112
    113                  self._LCTRL_xdt.InsertItem(index=0, label=_('name of xDT file'))
    114                  self._LCTRL_xdt.SetItem(index=0, column=1, label=filename)
    115
    116                  idx = 1
    117                  for line in xdt_file:
    118                          line = line.replace('\015','')
    119                          line = line.replace('\012','')
    120                          length, field, content = line[:3], line[3:7], line[7:]
    121
    122                          try:
    123                                  left = gmXdtMappings.xdt_id_map[field]
    124                          except KeyError:
    125                                  left = field
    126
    127                          try:
    128                                  right = gmXdtMappings.xdt_map_of_content_maps[field][content]
    129                          except KeyError:
    130                                  right = content
    131
    132                          self._LCTRL_xdt.InsertItem(index=idx, label=left)
    133                          self._LCTRL_xdt.SetItem(index=idx, column=1, label=right)
    134                          self._LCTRL_xdt.SetItem(index=idx, column=2, label=field)
    135                          self._LCTRL_xdt.SetItem(index=idx, column=3, label=content)
    136                          idx += 1
    137
    138                  xdt_file.close()
    139
    140                  self._LCTRL_xdt.SetColumnWidth(0, wx.LIST_AUTOSIZE)
    141                  self._LCTRL_xdt.SetColumnWidth(1, wx.LIST_AUTOSIZE)
    142
    143                  self._LCTRL_xdt.SetFocus()
    144                  self._LCTRL_xdt.SetItemState (
    145                          item = 0,
    146                          state = wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED,
    147                          stateMask = wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED
    148                  )
    149
    150                  self.filename = filename
    151          #--------------------------------------------------------------
    152          # event handlers
    153          #--------------------------------------------------------------
    154 -        def _on_load_button_pressed(self, evt):
    155                  self.load_file()
    156          #--------------------------------------------------------------
    157          # plugin API
    158          #--------------------------------------------------------------
    159 -        def repopulate_ui(self):
    160  #               if self.filename is None:
    161  #                       self.load_file()
    162                  return
    163  #=============================================================================
    164 -class gmXdtViewerPanel(wx.Panel):
    165 -        def __init__(self, parent, aFileName = None):
    166                  wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS)
    167
    168                  # our actual list
    169                  tID = wx.NewId()
    170                  self.list = gmXdtListCtrl(
    171                          self,
    172                          tID,
    173                          style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_VRULES
    174                  )#|wx.LC_HRULES)
    175
    176                  self.list.InsertColumn(0, _("XDT field"))
    177                  self.list.InsertColumn(1, _("XDT field content"))
    178
    179                  self.filename = aFileName
    180
    181                  # set up events
    182                  wx.EVT_SIZE(self, self.OnSize)
    183
    184                  wx.EVT_LIST_ITEM_SELECTED(self, tID, self.OnItemSelected)
    185                  wx.EVT_LIST_ITEM_DESELECTED(self, tID, self.OnItemDeselected)
    186                  wx.EVT_LIST_ITEM_ACTIVATED(self, tID, self.OnItemActivated)
    187                  wx.EVT_LIST_DELETE_ITEM(self, tID, self.OnItemDelete)
    188
    189                  wx.EVT_LIST_COL_CLICK(self, tID, self.OnColClick)
    190                  wx.EVT_LIST_COL_RIGHT_CLICK(self, tID, self.OnColRightClick)
    191  #               wx.EVT_LIST_COL_BEGIN_DRAG(self, tID, self.OnColBeginDrag)
    192  #               wx.EVT_LIST_COL_DRAGGING(self, tID, self.OnColDragging)
    193  #               wx.EVT_LIST_COL_END_DRAG(self, tID, self.OnColEndDrag)
    194
    195                  wx.EVT_LEFT_DCLICK(self.list, self.OnDoubleClick)
    196                  wx.EVT_RIGHT_DOWN(self.list, self.OnRightDown)
    197
    198                  if wx.Platform == '__WXMSW__':
    199                          wx.EVT_COMMAND_RIGHT_CLICK(self.list, tID, self.OnRightClick)
    200                  elif wx.Platform == '__WXGTK__':
    201                          wx.EVT_RIGHT_UP(self.list, self.OnRightClick)
    202
    203          #-------------------------------------------------------------------------
    204 -        def Populate(self):
    205
    206                  # populate list
    207                  items = self.__decode_xdt()
    208                  for item_idx in range(len(items),0,-1):
    209                          data = items[item_idx]
    210                          idx = self.list.InsertItem(info=wx.ListItem())
    211                          self.list.SetItem(index=idx, column=0, label=data[0])
    212                          self.list.SetItem(index=idx, column=1, label=data[1])
    213                          #self.list.SetItemData(item_idx, item_idx)
    214
    215                  # reaspect
    216                  self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
    217                  self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
    218
    219                  # show how to select an item
    220                  #self.list.SetItemState(5, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
    221
    222                  # show how to change the colour of a couple items
    223                  #item = self.list.GetItem(1)
    224                  #item.SetTextColour(wx.BLUE)
    225                  #self.list.SetItem(item)
    226                  #item = self.list.GetItem(4)
    227                  #item.SetTextColour(wxRED)
    228                  #self.list.SetItem(item)
    229
    230                  self.currentItem = 0
    231          #-------------------------------------------------------------------------
    232 -        def __decode_xdt(self):
    233                  if self.filename is None:
    234                          _log.error("Need name of file to parse !")
    235                          return None
    236
    237                  xDTFile = fileinput.input(self.filename)
    238                  items = {}
    239                  i = 1
    240                  for line in xDTFile:
    241                          # remove trailing CR and/or LF
    242                          line = string.replace(line,'\015','')
    243                          line = string.replace(line,'\012','')
    244                          length ,ID, content = line[:3], line[3:7], line[7:]
    245
    246                          try:
    247                                  left = xdt_id_map[ID]
    248                          except KeyError:
    249                                  left = ID
    250
    251                          try:
    252                                  right = xdt_map_of_content_maps[ID][content]
    253                          except KeyError:
    254                                  right = content
    255
    256                          items[i] = (left, right)
    257                          i = i + 1
    258
    259                  fileinput.close()
    260                  return items
    261          #-------------------------------------------------------------------------
    262 -        def OnRightDown(self, event):
    263                  self.x = event.GetX()
    264                  self.y = event.GetY()
    265                  item, flags = self.list.HitTest((self.x, self.y))
    266                  if flags & wx.LIST_HITTEST_ONITEM:
    267                          self.list.Select(item)
    268                  event.Skip()
    269          #-------------------------------------------------------------------------
    270 -        def getColumnText(self, index, col):
    271                  item = self.list.GetItem(index, col)
    272                  return item.GetText()
    273          #-------------------------------------------------------------------------
    274 -        def OnItemSelected(self, event):
    275                  self.currentItem = event.ItemIndex
    276          #-------------------------------------------------------------------------
    277 -        def OnItemDeselected(self, evt):
    278                  item = evt.GetItem()
    279
    280                  # Show how to reselect something we don't want deselected
    281  #               if evt.ItemIndex == 11:
    282  #                       wxCallAfter(self.list.SetItemState, 11, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)
    283          #-------------------------------------------------------------------------
    284 -        def OnItemActivated(self, event):
    285                  self.currentItem = event.ItemIndex
    286          #-------------------------------------------------------------------------
    287 -        def OnItemDelete(self, event):
    288                  pass
    289          #-------------------------------------------------------------------------
    290 -        def OnColClick(self, event):
    291                  pass
    292          #-------------------------------------------------------------------------
    293 -        def OnColRightClick(self, event):
    294                  item = self.list.GetColumn(event.GetColumn())
    295          #-------------------------------------------------------------------------
    296  #       def OnColBeginDrag(self, event):
    297  #               pass
    298          #-------------------------------------------------------------------------
    299  #       def OnColDragging(self, event):
    300  #               pass
    301          #-------------------------------------------------------------------------
    302  #       def OnColEndDrag(self, event):
    303  #               pass
    304          #-------------------------------------------------------------------------
    305 -        def OnDoubleClick(self, event):
    306                  event.Skip()
    307          #-------------------------------------------------------------------------
    308 -        def OnRightClick(self, event):
    309                  return
    310                  menu = wx.Menu()
    311                  tPopupID1 = 0
    312                  tPopupID2 = 1
    313                  tPopupID3 = 2
    314                  tPopupID4 = 3
    315                  tPopupID5 = 5
    316
    317                  # Show how to put an icon in the menu
    318                  item = wx.MenuItem(menu, tPopupID1,"One")
    319                  item.SetBitmap(images.getSmilesBitmap())
    320
    321                  menu.AppendItem(item)
    322                  menu.Append(tPopupID2, "Two")
    323                  menu.Append(tPopupID3, "ClearAll and repopulate")
    324                  menu.Append(tPopupID4, "DeleteAllItems")
    325                  menu.Append(tPopupID5, "GetItem")
    326                  wx.EVT_MENU(self, tPopupID1, self.OnPopupOne)
    327                  wx.EVT_MENU(self, tPopupID2, self.OnPopupTwo)
    328                  wx.EVT_MENU(self, tPopupID3, self.OnPopupThree)
    329                  wx.EVT_MENU(self, tPopupID4, self.OnPopupFour)
    330                  wx.EVT_MENU(self, tPopupID5, self.OnPopupFive)
    331                  self.PopupMenu(menu, wxPoint(self.x, self.y))
    332                  menu.DestroyLater()
    333                  event.Skip()
    334          #-------------------------------------------------------------------------
    335 -        def OnPopupOne(self, event):
    336                  print("FindItem:", self.list.FindItem(-1, "Roxette"))
    337                  print("FindItemData:", self.list.FindItemData(-1, 11))
    338          #-------------------------------------------------------------------------
    339 -        def OnPopupTwo(self, event):
    340                  pass
    341          #-------------------------------------------------------------------------
    342 -        def OnPopupThree(self, event):
    343                  self.list.ClearAll()
    344                  wx.CallAfter(self.PopulateList)
    345                  #wxYield()
    346                  #self.PopulateList()
    347          #-------------------------------------------------------------------------
    348 -        def OnPopupFour(self, event):
    349                  self.list.DeleteAllItems()
    350          #-------------------------------------------------------------------------
    351 -        def OnPopupFive(self, event):
    352                  item = self.list.GetItem(self.currentItem)
    353                  print(item.Text, item.Id, self.list.GetItemData(self.currentItem))
    354          #-------------------------------------------------------------------------
    355 -        def OnSize(self, event):
    356                  w,h = self.GetClientSize()
    357                  self.list.SetDimensions(0, 0, w, h)
    358  #======================================================
    359 -class gmXdtViewer(gmPlugin.cNotebookPlugin):
    360          """Plugin to encapsulate xDT list-in-panel viewer"""
    361
    362          tab_name = _('xDT viewer')
    363          required_minimum_role = 'non-clinical access'
    364
    365          @gmAccessPermissionWidgets.verify_minimum_required_role (
    366                  required_minimum_role,
    367                  activity = _('loading plugin <%s>') % tab_name,
    368                  return_value_on_failure = False,
    369                  fail_silently = False
    370          )
    371 -        def register(self):
    372                  gmPlugin.cNotebookPlugin.register(self)
    373          #-------------------------------------------------
    374
    375 -        def name(self):
    376                  return gmXdtViewer.tab_name
    377
    378 -        def GetWidget(self, parent):
    379                  self._widget = cXdtListPnl(parent, -1)
    380                  return self._widget
    381
    382 -        def MenuInfo(self):
    383                  return ('tools', _('&xDT viewer'))
    384
    385 -        def can_receive_focus(self):
    386                  return True
    387  #======================================================
    388  # main
    389  #------------------------------------------------------
    390  if __name__ == '__main__':
    391          from Gnumed.pycommon import gmCfg2
    392
    393          cfg = gmCfg2.gmCfgData()
    394          cfg.add_cli(long_options=['xdt-file='])
    395          #---------------------
    396          # set up dummy app
    397 -        class TestApp (wx.App):
    398 -                def OnInit (self):
    399
    400                          fname = ""
    401                          # has the user manually supplied a config file on the command line ?
    402                          fname = cfg.get(option = '--xdt-file', source_order = [('cli', 'return')])
    403                          if fname is not None:
    404                                  _log.debug('XDT file is [%s]' % fname)
    405                                  # file valid ?
    406                                  if not os.access(fname, os.R_OK):
    407                                          title = _('Opening xDT file')
    408                                          msg = _('Cannot open xDT file.\n'
    409                                                          '[%s]') % fname
    410                                          gmGuiHelpers.gm_show_error(msg, title)
    411                                          return False
    412                          else:
    413                                  title = _('Opening xDT file')
    414                                  msg = _('You must provide an xDT file on the command line.\n'
    415                                                  'Format: --xdt-file=<file>')
    416                                  gmGuiHelpers.gm_show_error(msg, title)
    417                                  return False
    418
    419                          frame = wx.Frame(
    420                                  parent = None,
    421                                  id = -1,
    422                                  title = _("XDT Viewer"),
    423                                  size = wx.Size(800,600)
    424                          )
    425                          pnl = gmXdtViewerPanel(frame, fname)
    426                          pnl.Populate()
    427                          frame.Show(1)
    428                          return True
    429          #---------------------
    430          try:
    431                  app = TestApp ()
    432                  app.MainLoop ()
    433          except Exception:
    434                  _log.exception('Unhandled exception.')
    435                  raise
    436
    437  #=============================================================================
    438