Gnumed.wxpython.gmSoapSTCWidgets

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

# Source Code for Module Gnumed.wxpython.gmSoapSTCWidgets

       1  # -*- coding: utf-8 -*-
       2  __doc__ = """GNUmed StyledTextCtrl subclass for SOAP editing.
       3
       4  based on: 11/21/2003 - Jeff Grimmett (grimmtooth@softhome.net)"""
       5  #================================================================
       6  __author__  = "K. Hilbert <Karsten.Hilbert@gmx.net>"
       7  __license__ = "GPL v2 or later (details at http://www.gnu.org)"
       8
       9  import logging
      10  import sys
      11
      12
      13  import wx
      14  import wx.stc
      15
      16
      17  if __name__ == '__main__':
      18          sys.path.insert(0, '../../')
      19  from Gnumed.business import gmSoapDefs
      20  from Gnumed.wxpython import gmKeywordExpansionWidgets
      21  from Gnumed.wxpython.gmTextCtrl import cUnicodeInsertion_TextCtrlMixin
      22
      23
      24  _log = logging.getLogger('gm.stc')
      25
      26  #================================================================
      27 -class cWxTextCtrlCompatibility_StcMixin():
      28
      29 -        def __init__(self, *args, **kwargs):
      30                  if not isinstance(self, wx.stc.StyledTextCtrl):
      31                          raise TypeError('[%s]: can only be applied to wx.stc.StyledTextCtrl, not [%s]' % (cWxTextCtrlCompatibility_StcMixin, self.__class__.__name__))
      32
      33          #--------------------------------------------------
      34          # wx.TextCtrl compatibility
      35          #--------------------------------------------------
      36 -        def GetValue(self):
      37                  _log.debug('%s.GetValue() - %s', cWxTextCtrlCompatibility_StcMixin, self.__class__.__name__)
      38                  return self.GetText()
      39
      40          #--------------------------------------------------
      41 -        def SetValue(self, value):
      42                  _log.debug('%s.SetValue() - %s', cWxTextCtrlCompatibility_StcMixin, self.__class__.__name__)
      43                  return self.SetText(value)
      44
      45          #--------------------------------------------------
      46 -        def WriteText(self, value):
      47                  return self.InsertText(self.CurrentPos, value)
      48
      49          #--------------------------------------------------
      50 -        def GetLastPosition(self):
      51                  return self.Length
      52
      53          LastPosition = property(GetLastPosition, lambda x:x)
      54
      55          #--------------------------------------------------
      56 -        def GetNumberOfLines(self):
      57                  return self.LineCount
      58
      59          #--------------------------------------------------
      60 -        def GetLineText(self, line_no):
      61                  return self.GetLine(line_no)
      62
      63          #--------------------------------------------------
      64 -        def GetInsertionPoint(self):
      65                  return self.CurrentPos
      66
      67 -        def SetInsertionPoint(self, position):
      68                  self.CurrentPos = position
      69
      70          InsertionPoint = property(GetInsertionPoint, SetInsertionPoint)
      71
      72          #--------------------------------------------------
      73 -        def ShowPosition(self, position):
      74                  #self.ScrollToLine(self.LineFromPosition(position))
      75                  self.CurrentPos = position
      76                  self.EnsureCaretVisible()
      77
      78          #--------------------------------------------------
      79 -        def IsMultiLine(self):
      80                  return True
      81
      82          #--------------------------------------------------
      83 -        def PositionToXY(self, position):
      84                  try:
      85                          #return wx.stc.StyledTextCtrl.PositionToXY(position)                    # does not work
      86                          #return wx.TextAreaBase.PositionToXY(position)                                  # does not work
      87                          return super(wx.TextAreaBase, self).PositionToXY(position)
      88                  except AttributeError:
      89                          # reimplement for wxPython 2.8,
      90                          # this is moot now, hwoever, since 2.8 returned an (x, y) tuple
      91                          return (True, self.GetColumn(position), self.LineFromPosition(position))
      92
      93          #--------------------------------------------------
      94 -        def Replace(self, start, end, replacement):
      95                  self.SetSelection(start, end)
      96                  self.ReplaceSelection(replacement)
      97                  wx.CallAfter(self.SetSelection, 0, 0)
      98
      99  #----------------------------------------------------------------------
     100 -class cSoapSTC(cUnicodeInsertion_TextCtrlMixin, gmKeywordExpansionWidgets.cKeywordExpansion_TextCtrlMixin, cWxTextCtrlCompatibility_StcMixin, wx.stc.StyledTextCtrl):
     101
     102          _MARKER_ADM = 0
     103          _MARKER_S = 1
     104          _MARKER_O = 2
     105          _MARKER_A = 3
     106          _MARKER_P = 4
     107          _MARKER_U = 5
     108          _MARKER_LINE_BG_LIGHT_GREY = 31
     109
     110          _DEFINED_MARKERS_MASK = (
     111                  _MARKER_ADM
     112                          |
     113                  _MARKER_S
     114                          |
     115                  _MARKER_O
     116                          |
     117                  _MARKER_A
     118                          |
     119                  _MARKER_P
     120                          |
     121                  _MARKER_U
     122                          |
     123                  _MARKER_LINE_BG_LIGHT_GREY
     124          )
     125
     126          _DEFINED_MARKER_NUMS = [
     127                  _MARKER_ADM,
     128                  _MARKER_S,
     129                  _MARKER_O,
     130                  _MARKER_A,
     131                  _MARKER_P,
     132                  _MARKER_U,
     133                  _MARKER_LINE_BG_LIGHT_GREY
     134          ]
     135          _SOAP_MARKER_NUMS = [
     136                  _MARKER_ADM,
     137                  _MARKER_S,
     138                  _MARKER_O,
     139                  _MARKER_A,
     140                  _MARKER_P,
     141                  _MARKER_U
     142          ]
     143          _SOAP2MARKER = {
     144                  None: _MARKER_ADM,
     145                  ' ': _MARKER_ADM,
     146                  '.': _MARKER_ADM,
     147                  's': _MARKER_S,
     148                  'o': _MARKER_O,
     149                  'a': _MARKER_A,
     150                  'p': _MARKER_P,
     151                  'u': _MARKER_U,
     152                  'S': _MARKER_S,
     153                  'O': _MARKER_O,
     154                  'A': _MARKER_A,
     155                  'P': _MARKER_P,
     156                  'U': _MARKER_U
     157          }
     158          _MARKER2SOAP = {
     159                  _MARKER_ADM: None,
     160                  _MARKER_S: 's',
     161                  _MARKER_O: 'o',
     162                  _MARKER_A: 'a',
     163                  _MARKER_P: 'p',
     164                  _MARKER_U: 'u'
     165          }
     166          _SOAPMARKER2BACKGROUND = {
     167                  _MARKER_ADM: False,
     168                  _MARKER_S: True,
     169                  _MARKER_O: False,
     170                  _MARKER_A: True,
     171                  _MARKER_P: False,
     172                  _MARKER_U: True
     173          }
     174
     175 -        def __init__(self, *args, **kwargs):
     176
     177                  # normalize wxGlade output
     178                  if args[2] == '':
     179                          l_args = list(args)
     180                          l_args[2] = wx.DefaultPosition
     181                          args = tuple(l_args)
     182                  wx.stc.StyledTextCtrl.__init__(self, *args, **kwargs)
     183                  cWxTextCtrlCompatibility_StcMixin.__init__(self)
     184                  gmKeywordExpansionWidgets.cKeywordExpansion_TextCtrlMixin.__init__(self)
     185                  cUnicodeInsertion_TextCtrlMixin.__init__(self)
     186
     187                  # wrapping and overflow
     188                  self.SetWrapMode(wx.stc.STC_WRAP_NONE)
     189                  # said to be problematic:
     190                  self.SetEdgeColumn(80)
     191                  self.SetEdgeColour('grey')
     192                  #self.SetEdgeMode(wx.stc.STC_EDGE_LINE)
     193                  self.SetEdgeMode(wx.stc.STC_EDGE_BACKGROUND)
     194
     195                  # EOL style
     196                  self.SetEOLMode(wx.stc.STC_EOL_LF)
     197                  #self.SetViewEOL(1)                                                                             # visual debugging
     198                  self.SetViewEOL(0)
     199
     200                  # whitespace handling
     201                  #self.SetViewWhiteSpace(wx.stc.STC_WS_VISIBLEAFTERINDENT)       # visual debugging
     202                  self.SetViewWhiteSpace(wx.stc.STC_WS_INVISIBLE)
     203                  #self.SetWhitespaceBackground(1, a_color)                                       # 1 = override lexer
     204                  #self.SetWhitespaceForeground(1, a_color)                                       # 1 = override lexer
     205
     206                  # caret handling
     207                  #self.SetCaretLineBackground('light goldenrod yellow')
     208                  self.SetCaretLineBackground('khaki')
     209                  self.SetCaretLineVisible(1)
     210
     211                  # margins
     212                  # left margin: 0 pixel widths
     213                  self.SetMarginLeft(0)
     214                  # margin 0: SOAP markers
     215                  self.SetMarginType(0, wx.stc.STC_MARGIN_SYMBOL)
     216                  self.SetMarginWidth(0, 16)
     217                  self.SetMarginMask(0, cSoapSTC._DEFINED_MARKERS_MASK)
     218                  # margin 1 and 2: additional 2-letter markers (not yet supported)
     219                  self.SetMarginType(1, wx.stc.STC_MARGIN_SYMBOL)
     220                  self.SetMarginMask(1, 0)
     221                  self.SetMarginWidth(1, 0)
     222                  self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL)
     223                  self.SetMarginMask(2, 0)
     224                  self.SetMarginWidth(2, 0)
     225
     226                  # markers
     227                  # can only use ASCII so far, so must make sure translations are ASCII:
     228                  self.MarkerDefine(cSoapSTC._MARKER_ADM, wx.stc.STC_MARK_CHARACTER + ord('.'), 'blue', 'white')
     229                  self.MarkerDefine(cSoapSTC._MARKER_S, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['s']), 'blue', 'grey96')
     230                  self.MarkerDefine(cSoapSTC._MARKER_O, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['o']), 'blue', 'white')
     231                  self.MarkerDefine(cSoapSTC._MARKER_A, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['a']), 'blue', 'grey96')
     232                  self.MarkerDefine(cSoapSTC._MARKER_P, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['p']), 'blue', 'white')
     233                  self.MarkerDefine(cSoapSTC._MARKER_U, wx.stc.STC_MARK_CHARACTER + ord(gmSoapDefs.soap_cat2l10n['u']), 'blue', 'grey96')
     234                  self.MarkerDefine(cSoapSTC._MARKER_LINE_BG_LIGHT_GREY, wx.stc.STC_MARK_BACKGROUND, 'grey96', 'grey96')
     235
     236                  # unset hotkeys we want to re-define
     237                  #self.CmdKeyClear('t', wx.stc.STC_SCMOD_CTRL)   # does not seem to work
     238                  self.__changing_SOAP_cat = False
     239                  self.__markers_of_prev_line = None
     240                  self.__ensure_has_all_soap_types = False
     241
     242                  # we do our own popup menu
     243                  self.UsePopUp(0)
     244                  self.__build_context_menu()
     245
     246                  # always keep one line of each of .SOAP around
     247                  self.SetText_from_SOAP()
     248
     249                  self.__register_events()
     250
     251                  # text expansion mixin
     252                  self.enable_keyword_expansions()
     253
     254          #-------------------------------------------------------
     255          # SOAP-enhanced text setting
     256          #-------------------------------------------------------
     257 -        def SetText(self, *args, **kwargs):
     258                  _log.debug('%s.SetText()', self.__class__.__name__)
     259                  wx.stc.StyledTextCtrl.SetText(self, *args, **kwargs)
     260
     261 -        def AddText(self, *args, **kwargs):
     262                  _log.debug('%s.AddText()', self.__class__.__name__)
     263                  wx.stc.StyledTextCtrl.AddText(self, *args, **kwargs)
     264
     265 -        def AddStyledText(self, *args, **kwargs):
     266                  _log.debug('%s.AddStyledText()', self.__class__.__name__)
     267                  wx.stc.StyledTextCtrl.AddStyledText(self, *args, **kwargs)
     268
     269 -        def InsertText(self, *args, **kwargs):
     270                  _log.debug('%s.InsertText()', self.__class__.__name__)
     271                  wx.stc.StyledTextCtrl.InsertText(self, *args, **kwargs)
     272
     273          #-------------------------------------------------------
     274 -        def ReplaceSelection(self, text):
     275                  sel_start, sel_end = self.GetSelection()
     276                  start_line = self.LineFromPosition(sel_start)
     277                  end_line = start_line + text.count('\n')
     278                  start_line_soap_cat = self.MarkerGet(start_line)
     279                  #_log.debug(u'replacing @ pos %s-%s with %s lines (line %s to line %s)', sel_start, sel_end, text.count(u'\n'), start_line, end_line)
     280                  wx.stc.StyledTextCtrl.ReplaceSelection(self, text)
     281                  if start_line != end_line:
     282                          for target_line in range(start_line, end_line):
     283                                  self.MarkerDelete(target_line, -1)
     284                                  self.__set_markers_of_line(target_line, start_line_soap_cat)
     285
     286          #-------------------------------------------------------
     287 -        def ReplaceTarget(self, *args, **kwargs):
     288                  _log.debug('%s.ReplaceTarget()', self.__class__.__name__)
     289                  wx.stc.StyledTextCtrl.ReplaceTarget(self, *args, **kwargs)
     290
     291 -        def ReplaceTargetRE(self, *args, **kwargs):
     292                  _log.debug('%s.ReplaceTargetRE()', self.__class__.__name__)
     293                  wx.stc.StyledTextCtrl.ReplaceTargetRE(self, *args, **kwargs)
     294
     295          #-------------------------------------------------------
     296          # external API
     297          #-------------------------------------------------------
     298 -        def SetText_from_SOAP(self, soap=None, sort_order=None):
     299                  # defaults
     300                  if soap is None:
     301                          #soap = {None: [u'']} # 'soap' will be added below by normalization
     302                          soap = {}
     303                  if sort_order is None:
     304                          sort_order = ['s', 'o', 'a', 'p', None, 'u']
     305
     306                  # normalize input
     307                  for cat in 'soap':
     308                          try:
     309                                  soap[cat]
     310                          except KeyError:
     311                                  soap[cat] = ['']
     312                  for cat in ['u', None]:
     313                          try:
     314                                  soap[cat]
     315                          except KeyError:
     316                                  soap[cat] = []
     317                  if '.' in soap:
     318                          soap[None].extend(soap['.'])
     319                          del soap['.']
     320                  if ' ' in soap:
     321                          soap[None].extend(soap[' '])
     322                          del soap[' ']
     323
     324                  # normalize sort order
     325                  for cat in 'soapu':
     326                          if cat not in sort_order:
     327                                  sort_order.append(cat)
     328                  if None not in sort_order:
     329                          sort_order.append(None)
     330
     331                  # sort and flatten
     332                  soap_lines = []
     333                  line_categories = []
     334                  for cat in sort_order:
     335                          lines = soap[cat]
     336                          if len(lines) == 0:
     337                                  continue
     338                          for line in lines:
     339                                  soap_lines.append(line.strip())
     340                                  line_categories.append(cat)
     341
     342                  _log.debug('%s.SetText_from_SOAP(): 1 controlled use of .SetText() follows', self.__class__.__name__)
     343                  self.SetText('\n'.join(soap_lines))
     344
     345                  for idx in range(len(line_categories)):
     346                          self.set_soap_cat_of_line(idx, line_categories[idx])
     347
     348          #-------------------------------------------------------
     349 -        def GetText_as_SOAP(self):
     350                  lines = self.GetText().split('\n')
     351                  soap = {}
     352                  for line_idx in range(len(lines)):
     353                          cat = self.get_soap_cat_of_line(line_idx)
     354                          if cat == -1:
     355                                  cat = 'u'
     356                          try:
     357                                  soap[cat]
     358                          except KeyError:
     359                                  soap[cat] = []
     360                          soap[cat].append(lines[line_idx])
     361                  return soap
     362
     363          soap = property(GetText_as_SOAP, lambda x:x)
     364
     365          #--------------------------------------------------------
     366 -        def _get_empty(self):
     367                  soap = self.GetText_as_SOAP()
     368                  for cat in soap:
     369                          if ''.join([ l.strip() for l in soap[cat] ]) != '':
     370                                  return False
     371                  return True
     372
     373          empty = property(_get_empty, lambda x:x)
     374
     375          #-------------------------------------------------------
     376 -        def sort_by_SOAP(self, sort_order=None):
     377                  self.SetText_from_SOAP(self.GetText_as_SOAP(), sort_order)
     378
     379          #-------------------------------------------------------
     380 -        def append_soap_line(self, soap_cat):
     381                  caret_pos = self.CurrentPos
     382                  self.GotoPos(self.Length)
     383                  self.AddText('\n')
     384                  self.set_soap_cat_of_line(self.LineCount, soap_cat)
     385
     386          #-------------------------------------------------------
     387          # generic helpers
     388          #-------------------------------------------------------
     389 -        def strip_trailing_whitespace_from_line(self, line):
     390                  line_text = self.GetLine(line)
     391                  line_start = self.PositionFromLine(line)
     392                  line_end = self.GetLineEndPosition(line)
     393                  self.SetTargetStart(line_start)
     394                  self.SetTargetEnd(line_end)
     395                  self.ReplaceTarget(line_text.rstrip())
     396
     397          #-------------------------------------------------------
     398 -        def caret_coords_in_stc(self):
     399                  return self.PointFromPosition(self.CurrentPos)
     400
     401          #-------------------------------------------------------
     402 -        def caret_coords_on_screen(self):
     403                  return self.ClientToScreen(self.caret_coords_in_stc())
     404
     405          #-------------------------------------------------------
     406          # internal helpers
     407          #-------------------------------------------------------
     477
     478          #-------------------------------------------------------
     488
     489          #-------------------------------------------------------
     490 -        def __get_clipboard_text(self):
     491                  if wx.TheClipboard.IsOpened():
     492                          _log.debug('clipboard already open')
     493                          return ''
     494                  if not wx.TheClipboard.Open():
     495                          _log.debug('cannot open clipboard')
     496                          return ''
     497                  data_obj = wx.TextDataObject()
     498                  got_it = wx.TheClipboard.GetData(data_obj)
     499                  if not got_it:
     500                          return ''
     501                  return data_obj.Text
     502
     503          #-------------------------------------------------------
     504          # context menu handlers
     505          #-------------------------------------------------------
     506 -        def __on_expand_keyword(self, evt):
     507                  self.attempt_expansion(show_list_if_needed = True)
     508
     509          #-------------------------------------------------------
     510 -        def __on_insert_unicode(self, evt):
     511                  self.mixin_insert_unicode_character()
     512
     513          #-------------------------------------------------------
     514 -        def __on_content2clipboard(self, evt):
     515                  txt = self.GetText().strip()
     516                  if txt == '':
     517                          return
     518                  self.CopyText(len(txt), txt)
     519
     520          #-------------------------------------------------------
     521 -        def __on_add_content2clipboard(self, evt):
     522                  txt = self.GetText().strip()
     523                  if txt == '':
     524                          return
     525                  txt = self.__get_clipboard_text() + '\n' + txt
     526                  self.CopyText(len(txt), txt)
     527
     528          #-------------------------------------------------------
     529 -        def __on_region2clipboard(self, evt):
     530                  self.Copy()
     531
     532          #-------------------------------------------------------
     533 -        def __on_add_region2clipboard(self, evt):
     534                  region = self.GetTextRange(self.SelectionStart, self.SelectionEnd)
     535                  if region.strip() == '':
     536                          return
     537                  txt = self.__get_clipboard_text() + '\n' + region
     538                  self.CopyText(len(txt), txt)
     539
     540          #-------------------------------------------------------
     541 -        def __on_line2clipboard(self, evt):
     542                  txt = self.GetLine(self.CurrentLine).strip()
     543                  if txt == '':
     544                          return
     545                  self.CopyText(len(txt), txt)
     546
     547          #-------------------------------------------------------
     548 -        def __on_add_line2clipboard(self, evt):
     549                  txt = self.GetLine(self.CurrentLine).strip()
     550                  if txt == '':
     551                          return
     552                  txt = self.__get_clipboard_text() + '\n' + txt
     553                  self.CopyText(len(txt), txt)
     554
     555          #-------------------------------------------------------
     556 -        def __on_make_line_Soap(self, evt):
     557                  self.set_soap_cat_of_line(self.CurrentLine, 's')
     558                  wx.CallAfter(self.sort_by_SOAP)
     559
     560          #-------------------------------------------------------
     561 -        def __on_make_line_sOap(self, evt):
     562                  self.set_soap_cat_of_line(self.CurrentLine, 'o')
     563                  wx.CallAfter(self.sort_by_SOAP)
     564
     565          #-------------------------------------------------------
     566 -        def __on_make_line_soAp(self, evt):
     567                  self.set_soap_cat_of_line(self.CurrentLine, 'a')
     568                  wx.CallAfter(self.sort_by_SOAP)
     569
     570          #-------------------------------------------------------
     571 -        def __on_make_line_soaP(self, evt):
     572                  self.set_soap_cat_of_line(self.CurrentLine, 'p')
     573                  wx.CallAfter(self.sort_by_SOAP)
     574
     575          #-------------------------------------------------------
     576 -        def __on_make_line_soapU(self, evt):
     577                  self.set_soap_cat_of_line(self.CurrentLine, 'u')
     578                  wx.CallAfter(self.sort_by_SOAP)
     579
     580          #-------------------------------------------------------
     581 -        def __on_make_line_soapADM(self, evt):
     582                  self.set_soap_cat_of_line(self.CurrentLine, '.')
     583                  wx.CallAfter(self.sort_by_SOAP)
     584
     585          #-------------------------------------------------------
     586 -        def __on_sort_by_soap(self, evt):
     587                  self.sort_by_SOAP()
     588
     589          #-------------------------------------------------------
     590          # marker related helpers
     591          #-------------------------------------------------------
     592 -        def _clone_markers(self, source, target):
     593                  self.MarkerDelete(target, -1)
     594                  self.__set_markers_of_line(target, self.MarkerGet(source))
     595
     596          #-------------------------------------------------------
     597 -        def __set_markers_of_line(self, line, markers):
     598                  for marker_num in cSoapSTC._DEFINED_MARKER_NUMS:
     599                          if markers & (1 << marker_num):
     600                                  self.MarkerAdd(line, marker_num)
     601
     602          #-------------------------------------------------------
     603 -        def get_soap_marker_of_line(self, line):
     604                  markers = self.MarkerGet(line)
     605                  for marker_num in cSoapSTC._SOAP_MARKER_NUMS:
     606                          if markers & (1 << marker_num):
     607                                  return marker_num
     608
     609                  return -1               # should only happen when deleting all lines -> STC empties out INCLUDING existing markers ...
     610
     611          #-------------------------------------------------------
     612 -        def get_soap_cat_of_line(self, line):
     613                  markers = self.MarkerGet(line)
     614                  for marker_num in cSoapSTC._SOAP_MARKER_NUMS:
     615                          if markers & (1 << marker_num):
     616                                  return cSoapSTC._MARKER2SOAP[marker_num]
     617
     618                  return -1               # should only happen when deleting all lines -> STC empties out INCLUDING existing markers ...
     619
     620          #-------------------------------------------------------
     621 -        def set_soap_cat_of_line(self, line, soap_category):
     622                  # remove all SOAP markers of this line
     623                  for marker_num in cSoapSTC._SOAP_MARKER_NUMS:
     624                          self.MarkerDelete(line, marker_num)
     625                  self.MarkerDelete(line, cSoapSTC._MARKER_LINE_BG_LIGHT_GREY)
     626                  # set desired marker
     627                  new_marker_num = cSoapSTC._SOAP2MARKER[soap_category]
     628                  self.MarkerAdd(line, new_marker_num)
     629                  if cSoapSTC._SOAPMARKER2BACKGROUND[new_marker_num]:
     630                          self.MarkerAdd(line, cSoapSTC._MARKER_LINE_BG_LIGHT_GREY)
     631                  return True
     632
     633          #-------------------------------------------------------
     634 -        def check_has_all_soap_types(self):
     635                  for marker_num in [ cSoapSTC._MARKER_S, cSoapSTC._MARKER_O, cSoapSTC._MARKER_A, cSoapSTC._MARKER_P ]:
     636                          if self.MarkerNext(0, (1 << marker_num)) == -1:
     637                                  return False
     638                  return True
     639
     640          #-------------------------------------------------------
     641 -        def ensure_has_all_soap_types(self):
     642                  self.__ensure_has_all_soap_types = False
     643                  self.sort_by_SOAP()
     644
     645          #-------------------------------------------------------
     646 -        def marker_count(self, marker):
     647                  line_count = 0
     648                  line_w_marker = -1
     649                  while True:
     650                          line_w_marker = self.MarkerNext(line_w_marker + 1, (1 << marker))
     651                          if line_w_marker == -1:
     652                                  break
     653                          line_count += 1
     654                  return line_count
     655
     656          #-------------------------------------------------------
     657 -        def soap_cat_count(self, soap_category):
     658                  marker = cSoapSTC._SOAP2MARKER[soap_category]
     659                  return self.marker_count(marker)
     660
     661          #-------------------------------------------------------
     662          # key handlers
     663          #-------------------------------------------------------
     664 -        def __handle_delete_key(self, evt):
     665
     666                  if evt.HasModifiers():
     667                          # we only handle DELETE w/o modifiers so far
     668                          evt.Skip()
     669                          return False
     670
     671                  sel_start, sel_end = self.GetSelection()
     672                  if sel_start != sel_end:
     673                          evt.Skip()
     674                          sel_start_line = self.LineFromPosition(sel_start)
     675                          sel_end_line = self.LineFromPosition(sel_end)
     676                          # within one line -> allow in any case
     677                          if sel_start_line == sel_end_line:
     678                                  return
     679                          sel_start_soap_marker = self.get_soap_marker_of_line(sel_start_line)
     680                          sel_end_soap_marker = self.get_soap_marker_of_line(sel_end_line)
     681                          if sel_start_soap_marker == sel_end_soap_marker:
     682                                  # across lines of the same SOAP type -> allow
     683                                  return
     684                          self.__ensure_has_all_soap_types = True
     685                          return
     686
     687                  curr_line = self.CurrentLine
     688                  if (curr_line + 1) == self.LineCount:                   # adjust for line index being 0-based
     689                          # we are on the last line, therefore we cannot end up
     690                          # pulling up a next line (and thereby remove the only
     691                          # line with a given SOAP category in case the last+1
     692                          # line would happen to be the only one of that category)
     693                          evt.Skip()
     694                          return False
     695
     696                  # in last column
     697                  caret_pos = self.GetColumn(self.CurrentPos)
     698                  max_pos = self.LineLength(curr_line) - 1
     699                  if caret_pos < max_pos:
     700                          # DELETE _inside_ a line (as opposed to at the
     701                          # _end_ of one) will not pull up the next line
     702                          # so no special SOAP checking
     703                          evt.Skip()
     704                          return False
     705
     706                  soap_marker_current_line = self.get_soap_marker_of_line(curr_line)
     707                  soap_marker_next_line = self.get_soap_marker_of_line(curr_line + 1)
     708                  if soap_marker_current_line == soap_marker_next_line:
     709                          # pulling up a line of the _same_ SOAP category
     710                          # is fine - and exactly what the user intended
     711                          # so allow that to happen (IOW no special DELETE
     712                          # handling)
     713                          evt.Skip()
     714                          return False
     715
     716                  # now we have got
     717                  # - a DELETE
     718                  # - without modifier keys
     719                  # - _not_ on the last line
     720                  # - in the last column of the current line
     721                  # - but the next line is of a different SOAP category
     722                  # so, do NOT evt.Skip() - IOW, ignore this DELETE
     723                  return True
     724
     725          #-------------------------------------------------------
     726 -        def __handle_backspace_key(self, evt):
     727
     728                  if evt.HasModifiers():
     729                          # we only handle BACKSPACE w/o modifiers so far
     730                          evt.Skip()
     731                          return False
     732
     733                  sel_start, sel_end = self.GetSelection()
     734                  if sel_start != sel_end:
     735                          evt.Skip()
     736                          sel_start_line = self.LineFromPosition(sel_start)
     737                          sel_end_line = self.LineFromPosition(sel_end)
     738                          # within one line -> allow in any case
     739                          if sel_start_line == sel_end_line:
     740                                  return
     741                          sel_start_soap_marker = self.get_soap_marker_of_line(sel_start_line)
     742                          sel_end_soap_marker = self.get_soap_marker_of_line(sel_end_line)
     743                          if sel_start_soap_marker == sel_end_soap_marker:
     744                                  # across lines of the same SOAP type -> allow
     745                                  return
     746                          self.__ensure_has_all_soap_types = True
     747                          return
     748
     749                  curr_line = self.LineFromPosition(self.CurrentPos)
     750                  if curr_line == 0:
     751                          # cannot BACKSPACE into line -1 anyway
     752                          evt.Skip()
     753                          return False
     754
     755                  if self.GetColumn(self.CurrentPos) > 0:
     756                          # not in first column, so not BACKSPACing into previous line
     757                          evt.Skip()
     758                          return False
     759
     760                  soap_marker_current_line = self.get_soap_marker_of_line(curr_line)
     761                  soap_marker_next_line = self.get_soap_marker_of_line(curr_line - 1)
     762                  if soap_marker_current_line == soap_marker_next_line:
     763                          # backspacing into previous line of the _same_ SOAP
     764                          # category is fine - and exactly what the user
     765                          # intended so allow that to happen (IOW no special
     766                          # DELETE handling)
     767                          evt.Skip()
     768                          return False
     769
     770                  # now we have got
     771                  # - a BACKSPACE
     772                  # - without modifier keys
     773                  # - _not_ on the first line
     774                  # - in the first column of the current line
     775                  # - but the previous line is of a different SOAP category
     776                  # so, do NOT evt.Skip() - IOW, ignore this BACKSPACE
     777                  return True
     778
     779          #-------------------------------------------------------
     780 -        def __handle_return_key_down(self, evt):
     781                  # currently we always want to pass on the RETURN (but remember the markers)
     782                  evt.Skip()
     783                  if evt.HasModifiers():
     784                          # we only handle RETURN w/o modifiers so far
     785                          self.__markers_of_prev_line = None
     786                          return
     787                  self.__markers_of_prev_line = self.MarkerGet(self.CurrentLine)
     788
     789          #-------------------------------------------------------
     790 -        def __handle_soap_category_key_down(self, key, line):
     791                  self.__changing_SOAP_cat = False
     792                  try:
     793                          soap_category = gmSoapDefs.l10n2soap_cat[key]
     794                  except KeyError:
     795                          if key.islower():
     796                                  key = key.upper()
     797                          else:
     798                                  key = key.lower()
     799                          try:
     800                                  soap_category = gmSoapDefs.l10n2soap_cat[key]
     801                          except KeyError:
     802                                  return
     803                  self.set_soap_cat_of_line(line, soap_category)
     804                  wx.CallAfter(self.sort_by_SOAP)
     805
     806          #-------------------------------------------------------
     814
     815          #-------------------------------------------------------
     823
     824          #-------------------------------------------------------
     825          # event setup and handlers
     826          #-------------------------------------------------------
     827 -        def __register_events(self):
     828                  # wxPython events
     829                  self.Bind(wx.EVT_KEY_DOWN, self._on_key_down)                   # happens before key gets into STC
     830                  #self.Bind(wx.EVT_CHAR, self._on_wx_char)                               # happens before char gets into STC
     831                  self.Bind(wx.EVT_CONTEXT_MENU, self._on_context_menu_activated)
     832
     833                  # STC events
     834                  self.Bind(wx.stc.EVT_STC_CHARADDED, self._on_stc_char_added)
     835                  self.Bind(wx.stc.EVT_STC_CHANGE, self._on_stc_change)
     836
     837                  #self.Bind(stc.EVT_STC_DO_DROP, self.OnDoDrop)
     838                  #self.Bind(stc.EVT_STC_DRAG_OVER, self.OnDragOver)
     839                  #self.Bind(stc.EVT_STC_START_DRAG, self.OnStartDrag)
     840                  #self.Bind(stc.EVT_STC_MODIFIED, self.OnModified)
     841
     842                  #self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
     843
     844          #-------------------------------------------------------
     845 -        def _on_wx_char(self, evt):
     846                  evt.Skip()
     847
     848          #-------------------------------------------------------
     849 -        def _on_key_down(self, evt):
     850
     851                  # CTRL-T has been pressed last, now another character has been pressed
     852                  if self.__changing_SOAP_cat:
     853                          self.__handle_soap_category_key_down(chr(evt.GetUnicodeKey()).lower(), self.CurrentLine)
     854                          # somehow put cursor into the changed (and possibly moved) line
     855                          return
     856
     857                  key = evt.KeyCode
     858
     859                  # ENTER
     860                  if key == wx.WXK_RETURN:
     861                          self.__handle_return_key_down(evt)
     862                          return
     863
     864                  # BACKSPACE
     865                  if key == wx.WXK_BACK:
     866                          self.__handle_backspace_key(evt)
     867                          return
     868
     869                  # DELETE
     870                  if key == wx.WXK_DELETE:
     871                          self.__handle_delete_key(evt)
     872                          return
     873
     874                  # MENU
     875                  if key == wx.WXK_MENU:
     876                          self.__handle_menu_key_down(evt)
     877                          return
     878
     879                  # CTRL-T: set Type
     880                  if key == ord('T'):
     881                          if evt.HasModifiers():
     882                                  if evt.CmdDown():               # CTRL-T or APPLE-T
     883                                          self.__changing_SOAP_cat = True
     884                                          return
     885
     886                  evt.Skip()                      # make sure unhandled keys get to the STC
     887
     888          #-------------------------------------------------------
     889 -        def _on_stc_char_added(self, evt):
     890                  evt.Skip()
     891                  key = evt.GetKey()
     892                  if key == 10:
     893                          # we cannot simply transfer the markers of the previous
     894                          # line (where we pressed RETURN) into the current line
     895                          # (which appeared after the RETURN) because the STC handles
     896                          # creating the "new" line differently based on where in the
     897                          # previous line RETURN was pressed (!) -- if it happened
     898                          # to be in position 0 (at the start of the line) the previous
     899                          # line is pushed DOWN and an empty line is inserted BEFORE
     900                          # the previous line (likely an optimization)
     901                          # hence we need to remember the markers of the real previous
     902                          # line from _before_ the new line gets created and use that
     903                          # auto-set the markers of the new line... |-)
     904                          if self.__markers_of_prev_line is None:
     905                                  return
     906                          self.__set_markers_of_line(self.CurrentLine - 1, self.__markers_of_prev_line)
     907                          self.__set_markers_of_line(self.CurrentLine, self.__markers_of_prev_line)
     908                          self.__markers_of_prev_line = None
     909                          return
     910
     911          #-------------------------------------------------------
     912 -        def _on_stc_change(self, evt):
     913                  if self.__ensure_has_all_soap_types:
     914                          wx.CallAfter(self.ensure_has_all_soap_types)
     915
     916          #-------------------------------------------------------
     917          #-------------------------------------------------------
     918          #-------------------------------------------------------
     919          #-------------------------------------------------------
     920          # unused:
     921          #-------------------------------------------------------
     922 -        def OnDestroy(self, evt):
     923                  # This is how the clipboard contents can be preserved after
     924                  # the app has exited.
     925                  wx.TheClipboard.Flush()
     926                  evt.Skip()
     927
     928
     929 -        def OnStartDrag(self, evt):
     930                  #self.log.write("OnStartDrag: %d, %s\n"
     931                  #                          % (evt.GetDragAllowMove(), evt.GetDragText()))
     932
     933                  if debug and evt.GetPosition() < 250:
     934                          evt.SetDragAllowMove(False)             # you can prevent moving of text (only copy)
     935                          evt.SetDragText("DRAGGED TEXT") # you can change what is dragged
     936                          #evt.SetDragText("")                     # or prevent the drag with empty text
     937
     938
     939 -        def OnDragOver(self, evt):
     940                  #self.log.write(
     941                  #       "OnDragOver: x,y=(%d, %d)  pos: %d      DragResult: %d\n"
     942                  #       % (evt.GetX(), evt.GetY(), evt.GetPosition(), evt.GetDragResult())
     943                  #       )
     944
     945                  if debug and evt.GetPosition() < 250:
     946                          evt.SetDragResult(wx.DragNone)   # prevent dropping at the beginning of the buffer
     947
     948
     949 -        def OnDoDrop(self, evt):
     950                  #self.log.write("OnDoDrop: x,y=(%d, %d) pos: %d  DragResult: %d\n"
     951                  #                          "\ttext: %s\n"
     952                  #                          % (evt.GetX(), evt.GetY(), evt.GetPosition(), evt.GetDragResult(),
     953                  #                                 evt.GetDragText()))
     954
     955                  if debug and evt.GetPosition() < 500:
     956                          evt.SetDragText("DROPPED TEXT")  # Can change text if needed
     957                          #evt.SetDragResult(wx.DragNone)  # Can also change the drag operation, but it
     958                                                                                           # is probably better to do it in OnDragOver so
     959                                                                                           # there is visual feedback
     960
     961                          #evt.SetPosition(25)                     # Can also change position, but I'm not sure why
     962                                                                                           # you would want to...
     963
     964
     965 -        def OnModified(self, evt):
     966                  #self.log.write("""OnModified
     967  #               Mod type:         %s
     968  #               At position:  %d
     969  #               Lines added:  %d
     970  #               Text Length:  %d
     971  #               Text:             %s\n""" % ( self.transModType(evt.GetModificationType()),
     972  #                                                                 evt.GetPosition(),
     973  #                                                                 evt.GetLinesAdded(),
     974  #                                                                 evt.GetLength(),
     975  #                                                                 repr(evt.GetText()) ))
     976                  pass
     977
     978
     979 -        def transModType(self, modType):
     980                  st = ""
     981                  table = [(stc.STC_MOD_INSERTTEXT, "InsertText"),
     982                                   (stc.STC_MOD_DELETETEXT, "DeleteText"),
     983                                   (stc.STC_MOD_CHANGESTYLE, "ChangeStyle"),
     984                                   (stc.STC_MOD_CHANGEFOLD, "ChangeFold"),
     985                                   (stc.STC_PERFORMED_USER, "UserFlag"),
     986                                   (stc.STC_PERFORMED_UNDO, "Undo"),
     987                                   (stc.STC_PERFORMED_REDO, "Redo"),
     988                                   (stc.STC_LASTSTEPINUNDOREDO, "Last-Undo/Redo"),
     989                                   (stc.STC_MOD_CHANGEMARKER, "ChangeMarker"),
     990                                   (stc.STC_MOD_BEFOREINSERT, "B4-Insert"),
     991                                   (stc.STC_MOD_BEFOREDELETE, "B4-Delete")
     992                                   ]
     993
     994                  for flag,text in table:
     995                          if flag & modType:
     996                                  st = st + text + " "
     997
     998                  if not st:
     999                          st = 'UNKNOWN'
    1000
    1001                  return st
    1002
    1003  #----------------------------------------------------------------------
    1004  #----------------------------------------------------------------------
    1005  #----------------------------------------------------------------------
    1006  if wx.Platform == '__WXMSW__':
    1007          face1 = 'Arial'
    1008          face2 = 'Times New Roman'
    1009          face3 = 'Courier New'
    1010          pb = 12
    1011  else:
    1012          face1 = 'Helvetica'
    1013          face2 = 'Times'
    1014          face3 = 'Courier'
    1015          pb = 14
    1016
    1017
    1018  _USE_PANEL = 1
    1019
    1020 -def runTest(frame, nb):
    1021          if not _USE_PANEL:
    1022                  ed = p = cSoapSTC(nb, -1)
    1023
    1024          else:
    1025                  p = wx.Panel(nb, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE)
    1026                  ed = cSoapSTC(p, -1, log)
    1027                  s = wx.BoxSizer(wx.HORIZONTAL)
    1028                  s.Add(ed, 1, wx.EXPAND)
    1029                  p.SetSizer(s)
    1030                  p.SetAutoLayout(True)
    1031
    1032
    1033          #ed.SetBufferedDraw(False)
    1034          #ed.StyleClearAll()
    1035          #ed.SetScrollWidth(800)
    1036          #ed.SetWrapMode(True)
    1037          #ed.SetUseAntiAliasing(False)
    1038          #ed.SetViewEOL(True)
    1039
    1040          #ed.CmdKeyClear(stc.STC_KEY_BACK,
    1041          #                               stc.STC_SCMOD_CTRL)
    1042          #ed.CmdKeyAssign(stc.STC_KEY_BACK,
    1043          #                                stc.STC_SCMOD_CTRL,
    1044          #                                stc.STC_CMD_DELWORDLEFT)
    1045
    1046          ed.SetText(demoText)
    1047
    1048          if wx.USE_UNICODE:
    1049                  import codecs
    1050                  decode = codecs.lookup("utf-8")[1]
    1051
    1052                  ed.GotoPos(ed.GetLength())
    1053                  ed.AddText("\n\nwx.StyledTextCtrl can also do Unicode:\n")
    1054                  uniline = ed.GetCurrentLine()
    1055                  unitext, l = decode('\xd0\x9f\xd0\xb8\xd1\x82\xd0\xbe\xd0\xbd - '
    1056                                                          '\xd0\xbb\xd1\x83\xd1\x87\xd1\x88\xd0\xb8\xd0\xb9 '
    1057                                                          '\xd1\x8f\xd0\xb7\xd1\x8b\xd0\xba \xd0\xbf\xd1\x80\xd0\xbe\xd0\xb3\xd1\x80\xd0\xb0\xd0\xbc\xd0\xbc\xd0\xb8\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb0\xd0\xbd\xd0\xb8\xd1\x8f!\n\n')
    1058                  ed.AddText('\tRussian: ')
    1059                  ed.AddText(unitext)
    1060                  ed.GotoPos(0)
    1061          #else:
    1062          #        #ed.StyleSetFontEncoding(stc.STC_STYLE_DEFAULT, wx.FONTENCODING_KOI8)
    1063          #        #text = u'\u041f\u0438\u0442\u043e\u043d - \u043b\u0443\u0447\u0448\u0438\u0439 \u044f\u0437\u044b\u043a \n\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f!'
    1064          #        #text = text.encode('koi8-r')
    1065          #        #ed.StyleSetFontEncoding(stc.STC_STYLE_DEFAULT, wx.FONTENCODING_BIG5)
    1066          #        #text = u'Python \u662f\u6700\u597d\u7684\u7de8\u7a0b\u8a9e\u8a00\uff01'
    1067          #        #text = text.encode('big5')
    1068          #        ed.GotoPos(ed.GetLength())
    1069          #        ed.AddText('\n\n' + text)
    1070
    1071          ed.EmptyUndoBuffer()
    1072
    1073          # make some styles
    1074          ed.StyleSetSpec(stc.STC_STYLE_DEFAULT, "size:%d,face:%s" % (pb, face3))
    1075          ed.StyleClearAll()
    1076          ed.StyleSetSpec(1, "size:%d,bold,face:%s,fore:#0000FF" % (pb, face1))
    1077          ed.StyleSetSpec(2, "face:%s,italic,fore:#FF0000,size:%d" % (face2, pb))
    1078          ed.StyleSetSpec(3, "face:%s,bold,size:%d" % (face2, pb))
    1079          ed.StyleSetSpec(4, "face:%s,size:%d" % (face1, pb-1))
    1080
    1081          # Now set some text to those styles...  Normally this would be
    1082          # done in an event handler that happens when text needs displayed.
    1083          ed.StartStyling(98, 0xff)
    1084          ed.SetStyling(6, 1)      # set style for 6 characters using style 1
    1085
    1086          ed.StartStyling(190, 0xff)
    1087          ed.SetStyling(20, 2)
    1088
    1089          ed.StartStyling(310, 0xff)
    1090          ed.SetStyling(4, 3)
    1091          ed.SetStyling(2, 0)
    1092          ed.SetStyling(10, 4)
    1093
    1094
    1095          # line numbers in the margin
    1096          ed.SetMarginType(0, stc.STC_MARGIN_NUMBER)
    1097          ed.SetMarginWidth(0, 22)
    1098          ed.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "size:%d,face:%s" % (pb-2, face1))
    1099
    1100          # setup some markers
    1101          ed.SetMarginType(1, stc.STC_MARGIN_SYMBOL)
    1102          ed.MarkerDefine(0, stc.STC_MARK_ROUNDRECT, "#CCFF00", "RED")
    1103          ed.MarkerDefine(1, stc.STC_MARK_CIRCLE, "FOREST GREEN", "SIENNA")
    1104          ed.MarkerDefine(2, stc.STC_MARK_SHORTARROW, "blue", "blue")
    1105          ed.MarkerDefine(3, stc.STC_MARK_ARROW, "#00FF00", "#00FF00")
    1106
    1107          # put some markers on some lines
    1108          ed.MarkerAdd(17, 0)
    1109          ed.MarkerAdd(18, 1)
    1110          ed.MarkerAdd(19, 2)
    1111          ed.MarkerAdd(20, 3)
    1112          ed.MarkerAdd(20, 0)
    1113
    1114
    1115          # and finally, an indicator or two
    1116          ed.IndicatorSetStyle(0, stc.STC_INDIC_SQUIGGLE)
    1117          ed.IndicatorSetForeground(0, wx.RED)
    1118          ed.IndicatorSetStyle(1, stc.STC_INDIC_DIAGONAL)
    1119          ed.IndicatorSetForeground(1, wx.BLUE)
    1120          ed.IndicatorSetStyle(2, stc.STC_INDIC_STRIKE)
    1121          ed.IndicatorSetForeground(2, wx.RED)
    1122
    1123          ed.StartStyling(836, stc.STC_INDICS_MASK)
    1124          ed.SetStyling(10, stc.STC_INDIC0_MASK)
    1125          ed.SetStyling(8, stc.STC_INDIC1_MASK)
    1126          ed.SetStyling(10, stc.STC_INDIC2_MASK | stc.STC_INDIC1_MASK)
    1127
    1128
    1129          # some test stuff...
    1130          if debug:
    1131                  print("GetTextLength(): ", ed.GetTextLength(), len(ed.GetText()))
    1132                  print("GetText(): ", repr(ed.GetText()))
    1133                  print()
    1134                  print("GetStyledText(98, 104): ", repr(ed.GetStyledText(98, 104)), len(ed.GetStyledText(98, 104)))
    1135                  print()
    1136                  print("GetCurLine(): ", repr(ed.GetCurLine()))
    1137                  ed.GotoPos(5)
    1138                  print("GetCurLine(): ", repr(ed.GetCurLine()))
    1139                  print()
    1140                  print("GetLine(1): ", repr(ed.GetLine(1)))
    1141                  print()
    1142                  ed.SetSelection(25, 35)
    1143                  print("GetSelectedText(): ", repr(ed.GetSelectedText()))
    1144                  print("GetTextRange(25, 35): ", repr(ed.GetTextRange(25, 35)))
    1145                  print("FindText(0, max, 'indicators'): ", end=' ')
    1146                  print(ed.FindText(0, ed.GetTextLength(), "indicators"))
    1147                  if wx.USE_UNICODE:
    1148                          end = ed.GetLength()
    1149                          start = ed.PositionFromLine(uniline)
    1150                          print("GetTextRange(%d, %d): " % (start, end), end=' ')
    1151                          print(repr(ed.GetTextRange(start, end)))
    1152
    1153
    1154          wx.CallAfter(ed.GotoPos, 0)
    1155          return p
    1156
    1157
    1158  #----------------------------------------------------------------------
    1159  overview = """\
    1160  <html><body>
    1161  Once again, no docs yet.  <b>Sorry.</b>  But <a href="data/stc.h.html">this</a>
    1162  and <a href="http://www.scintilla.org/ScintillaDoc.html">this</a> should
    1163  be helpful.
    1164  </body><html>
    1165  """
    1166
    1167  #===================================================
    1168  # main
    1169  #---------------------------------------------------
    1170  if __name__ == '__main__':
    1171
    1172          if len(sys.argv) < 2:
    1173                  sys.exit()
    1174
    1175          if sys.argv[1] != 'test':
    1176                  sys.exit()
    1177
    1178          import wx.lib.colourdb
    1179
    1180          from Gnumed.pycommon import gmI18N
    1181          gmI18N.activate_locale()
    1182          gmI18N.install_domain(domain = 'gnumed')
    1183
    1184          #-----------------------------------------------
    1185 -        def test_stc():
    1186                  app = wx.PyWidgetTester(size = (600, 600))
    1187                  wx.lib.colourdb.updateColourDB()
    1188                  #print wx.lib.colourdb.getColourList()
    1189                  app.SetWidget(cSoapSTC, -1, (100,50))
    1190                  app.MainLoop()
    1191                  return True
    1192
    1193  #               app = wx.PyWidgetTester(size = (200, 50))
    1194  #               tc = cTextCtrl(app.frame, -1)
    1195  #               #tc.enable_keyword_expansions()
    1196  #               app.frame.Show(True)
    1197  #               app.MainLoop()
    1198  #               return True
    1199
    1200          #-----------------------------------------------
    1201          test_stc()
    1202