Liz, on second thoughts, don't install gnuMed. Lets take the opportunity to 
remove all the gnuMed dependencies so that someone not able to access CVS can 
download the demo.

I've removed the dependenceis from the SOAP control file which I enclose. 
Substitute this for the old file and run it again and send me the error 
messages.

Richard

On Tue, 1 Mar 2005 07:58 am, you wrote:
> On Tuesday 01 March 2005 07:48, Richard Terry wrote:
> > Liz, I'm going to post this to the list to get extra help, but note my
> > comments below:
> >
> > On Mon, 28 Feb 2005 09:45 pm, you wrote:
> > > > Anway, send me the errors.
> > >
> > > [EMAIL PROTECTED] tar -zxvf guidemo26feb05.tar.gz
> > >
> > > gzip: stdin: not in gzip format
> > > tar: Child returned status 1
> > > tar: Error exit delayed from previous errors
> >
> > ===========================================
> > (I think this usually means there is something wrong with the file,
> > however I'm assuming it untarrred properly. I untarred the file to
> > my /gnumed/gnumed/test-area/ and it unpacked correctly and ran with
> > the ./rundemo.
> > =============================================
> >
> > > [EMAIL PROTECTED] ./rundemo
> > > log file is [/home/liz/.gui-demo/gui-demo.log]
> > > Traceback (most recent call last):
> > >   File "gui-demo.py", line 24, in ?
> > >     import SOAPTextCtrlwx25
> > >   File "/mnt/hdb3/downloads/gnumed/gui_demo/SOAPTextCtrlwx25.py", line
> > > 33, in ?
> > >     from Gnumed.pycommon import gmLog, gmI18N
> > > ImportError: No module named Gnumed.pycommon
> > > Liz
> >
> > ================================================
> > 2): This proobably means you don't have gnuMed installed properly on your
> > machine, as it cannot find the /usr/lib/python2.x/site-packages/ link to
> > the gnuMed cvs tree
> >
> > This is how my gnuMed is linked to my python site-packages:
> >
> > [EMAIL PROTECTED]:/usr/lib/python2.3/site-packages$ ls -al Gnumed
> > lrwxrwxrwx    1 root     root           35 Jul 27  2004 Gnumed
> > -> /home/richard/gnumed/gnumed/client/
> >
> > Hope this helps. I suspect that this is all it is and that it is because
> > you have it remotely mounted without the links.
> >
> > richard
>
> I haven't got gnumed installed!
#!/usr/bin/env python
##     Text control for SOAP notes
##     Copyright (C) 2004 Ian Haywood

##     This program is free software; you can redistribute it and/or modify
##     it under the terms of the GNU General Public License as published by
##     the Free Software Foundation; either version 2 of the License, or
##     (at your option) any later version.

##     This program is distributed in the hope that it will be useful,
##     but WITHOUT ANY WARRANTY; without even the implied warranty of
##     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
##     GNU General Public License for more details.

##     You should have received a copy of the GNU General Public License
##     along with this program; if not, write to the Free Software
##     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

"""
This widget allows the display of SOAP notes, or similar, with
highlighted headings which are protected from user editing.
A pluggable autocompletion mechanism is provided
"""

import string, re, time

from wxPython.wx import *
from wxPython.stc import *

#if __name__ == "__main__":
import sys
sys.path.append ("../..")
#from Gnumed.pycommon import gmLog, gmI18N

STYLE_HEADER=1
STYLE_TEXT=2
STYLE_EMBED=4
STYLE_KEYWORD=3

TEXT=1
NUMBER=2
DATE=3
SELECTION=4

class myTimer (wxTimer):

    def __init__ (self, funct):
        self.funct = funct
        wxTimer.__init__ (self)
        self.Start (300, wxTIMER_ONE_SHOT)

    def Notify (self):
        self.funct ()



class SOAPTextCtrl (wxStyledTextCtrl):
    def OnRightClick(self, event):
		self.log.WriteText("OnRightClick\n")
		print "Hey, you right clicked on me"
    def ReplaceText (self, start, length, text, style=-1, space=0):
        """
        Oddly, the otherwise very rich wxSTC API does not provide an
        easy way to replace text, so we provide it here.

        @param start: the position in the text to start from
        @param length: the length of the string to replace
        @param text: the new string
        @param style: the style for the replaced string
        """
        self.SetTargetStart (start)
        self.SetTargetEnd (start+length)
        if space:
            self.ReplaceTarget (text + " ")
        else:
            self.ReplaceTarget (text)
        if style > -1:
            self.StartStyling (start, 0xFF)
            self.SetStyling (len (text), style)

    def __get_word_by_style (self, pos, style):
        oldpos = pos
        s = ''
        m = self.GetLength ()
        while pos < m and self.GetStyleAt (pos) == style:
            s += chr (self.GetCharAt (pos))
            pos += 1
        pos = oldpos-1
        while pos >= 0  and self.GetStyleAt (pos) == style:
            s = chr (self.GetCharAt (pos)) + s
            pos -= 1
        return pos+1, s

    def __get_word_by_lex (self, pos):
        s = ''
        pos = pos-1
        while pos >= 0  and chr (self.GetCharAt (pos)) in string.letters:
            s = chr (self.GetCharAt (pos)) + s
            pos -= 1
        return pos+1, s

    def __calc_section (self, pos):
        self.section_end = pos
        m = self.GetLength ()
        while self.section_end < m and self.GetStyleAt (self.section_end) != STYLE_HEADER:
            self.section_end += 1
        self.section_end -=1
        self.section_start = pos-1
        while self.section_start >= 0 and self.GetStyleAt (self.section_start) != STYLE_HEADER:
            self.section_start -= 1
        section_name = ''
        pos = self.section_start -1
        self.section_start += 1
        while pos >= 0  and chr (self.GetCharAt (pos)) in string.letters:
            section_name = chr (self.GetCharAt (pos)) + section_name
            pos -= 1
        self.section = 0
        while self.headers[self.section][0] != section_name:
            self.section += 1
            if self.section >= len (self.headers):
                sys.exit (1)

    def __init__ (self, parent, id, pos=wxDefaultPosition, size= None, style=0):
        """
        @type parent: wxWindow
        @param parent: the parent widget
        @type id: number
        @param id: the window ID
        @type pos: wxPoint
        @param pos: the window position
        @type size: wxSize
        @param size: the window's size
        @type style: integer
        @param style: the window's style

		extra parameters by subclassing, and overriding GetHeaders(), GetSummary()
		
        """
        if size is None:
            size = wxSize (400, 200)
        wxStyledTextCtrl.__init__ (self, parent, id, pos, size, style)
        self.parent = parent
	id = self.GetId ()

        self.SetWrapMode (wxSTC_WRAP_WORD)
        self.StyleSetSpec (STYLE_HEADER, "fore:#1329f1,bold,face:Times,size:10") #7F11010
        self.StyleSetSpec (STYLE_EMBED, "fore:# f15e15")# 4040B0")
        self.StyleSetSpec (STYLE_KEYWORD, "fore:# 1329f1")#3030A0")
	"""
	StyleSetSpec(styleNum, spec)
	it takes a string object spec and applies the information from the string as the attributes for the style specified by the integer parameter styleNum. Returns None.

	The specification string has various tokens, some with options.

	bold                    turns on bold
	italic                  turns on italics
	fore:#RRGGBB            sets the foreground colour
	back:#RRGGBB            sets the background colour
	face:[facename]         sets the font face name to use
	size:[num]              sets the font size in points
	eol                     turns on eol filling
	underline               turns on underlining

	"""
        self.SetEOLMode (wxSTC_EOL_LF)
	"""
	SetEOLMode(eolMode)

	Sets the line ending mode for the active Document to the integer value eolMode. It is important to realize that this is NOT a global setting, but is done on a document-by-document basis. When a new document is created its internal EOL mode flag is set to LF only (wxSTC_EOL_LF) if the OS is Unix or to CRLF (wxSTC_EOL_CRLF) otherwise (this is a result of a compile-time #ifdef in the Scintilla code).

	If you are concerned about cross-platform compatibility, you may wish to programmatically set this every time a new Document is created. Otherwise, if your app is run on a Mac the EOL mode will be set to CRLF.
	"""

        self.SetMarginWidth (10, 0)
        self.AutoCompStops ("()<>,.;:'\"[]{}\\|/? [EMAIL PROTECTED]&*")
	"""
	If a character from the set of characters in stopChars is pressed by the user, then the autocomplete operation is cancelled; just as if AutoCompCancel() was invoked programmatically. Returns None.

	"""
        self.__embeds = {}
        self.autocompstr = ''
        self.__data = {}
        self.__text = None
        self.__we_are_new = 1
        self.headers = self.GetHeaders ()
        self.timer = None
        self.__popup = None
        self.replace_len = 0
        self.popup = 0
        self.AutoCompSetSeparator (10)
	"""
	AutoCompSetSeparator(separatorCharacter)

	Sets the separator character that is used to separate strings in the itemList passed to AutoCompShow or UserListShow. If this method is not used then the default is the space character. Returns None. 
	"""
        EVT_KEY_DOWN (self, self.__keypressed)
        EVT_LEFT_DOWN (self, self.__mouse_down)
        EVT_STC_USERLISTSELECTION (self, id, self.__userlist)
	"""
	EVT_STC_USERLISTSELECTION(win, id, func)

	Fired after an item in a user list is selected. Use wxStyledTextCtrl.GetListType and .GetText to retrieve the values of the listType and text attributes set by this event. Note: at the time of this writing (Nov 2002) GetListType will always return 0. This will probably be fixed by the time you read this, unless you are using an old version of wxPython.
	"""




    def GetHeaders (self):
        """
        Sets the list of headers, must be overrided by descendants
        - header: the string labelling the section
        - type: one of TEXT, NUMBER, DATE, SELECTION
        SELECTION behaves like text except the match provider result replaces
        all text in that section
        @return: list of tuple (header, type, match provider, poppers)
        """
        return []


    def GetSummary (self, data):
        """
        Returns a brief summary string for displaying in embeds
        """
        return 'SOAP'


    def Process (self, data):
        """
        Performs processing: i.e. commits data to the backend
        """
        pass
    
    def ClearAll (self):
        """
        Clears the widget and writes the headers again
        """
        wxStyledTextCtrl.ClearAll (self)
        self.SetEOLMode (wxSTC_EOL_LF)
        self.__write_headings ()



    def set_data (self, data):
        """
        Clears the contents of the widget,
        and sets the values of the various sections

        @type data: dictionary of strings
        @param data: the text to insert, keyed by header name
        """
        wxStyledTextCtrl.ClearAll (self)
        self.SetEOLMode (wxSTC_EOL_LF)
        self.__write_headings (data or {})
        if data and data.has_key ('__data'):
            self.__we_are_new = 0
            self.__data = data['__data']
        if data and data.has_key ('__text'):
            self.__text = data['__text']

    def __write_headings (self, data={}):
	"""
	@type data - a dictionary of strings
	@param data: the text to insert, keyed by header name.
	data is state information for a child SOAPTextCtrl popup,
	stored in the parent's self._embeds map under the child's summary text.
	e.g. for SOAP headers or S, O, A, P, for recall it is reason, date.
	"""
	
        pos = 0

	"""write the header and it's data, and set the header text style to STYLE_HEADER
	"""
        for heading, type, matcher, poppers in self.headers:
            if data.has_key (heading):
                text = "%s: %s\n" % (heading, data[heading])
            else:
                text = "%s:\n" % heading
            self.AddText (text)
            self.StartStyling (pos, 0xFF)
            self.SetStyling (len (heading)+1, STYLE_HEADER)
            pos += len (text)
           
	"""initialize section and cursor position
	to first section, end of first sections' data."""   
        self.section = 0
        self.section_start = len (self.headers[0][0])+1
        self.section_end = len (self.headers[0][0])+1
        if data.has_key (self.headers[0][0]):
            self.section_end += 1+len (data[self.headers[0][0]])
        self.GotoPos (self.section_end)
        
    def __validate_number (self):
        s = ''
        pos = self.section_start
        while pos < self.GetLength () and self.GetCharAt (pos) != 10: 
            s += chr (self.GetCharAt (pos))
            pos += 1
        s = s.strip ()
        try:
            self.__data[self.headers[self.section][0]] = float (s)
            return 1
        except:
            #wxMessageBox ("%s is not a valid number" % s, "Invalid entry", wxICON_ERROR | wxOK)
            wxBell ()
            return 0

    def __validate_date (self):
        s = ''
        pos = self.section_start
        while pos < self.GetLength () and self.GetCharAt (pos) != 10: 
            s += chr (self.GetCharAt (pos))
            pos += 1
        s_len = len (s)
        s = s.strip ()
        t = time.localtime (time.time ())
        year = -1
        unit = ''
        day = t[2]
        month = t[1]
        year = t[0]
        m = re.match ("([0-9]+)/([0-9]+)$", s)
        if m:
            day = int (m.group (1))
            month = int (m.group (2))
            if month < t[1] or (month == t[1] and day < t[2]):
                year +=1
            self.display_date (day, month, year, s_len)
            return 1
        else:
            m = re.match ("([0-9]+)([%s])" % _('dwmy'), s)
            if m:
                incr = int (m.group (1))
                unit = m.group (2)
            else:
                m = re.match ("-([0-9]+)([%s])" % _('dwmy'), s)
                if m:
                    incr = -int (m.group (1))
                    unit = m.group (2)
            if unit:
                incr *= 86400 # day in seconds
                if unit == _('dwmy')[1]:
                    incr *= 7 # a week is 7 days
                elif unit == _('dwmy')[2]:
                    incr *= 30
                elif unit == _('dwmy')[3]:
                    incr *= 365
                # now we have offset in seconds
                t = time.time () # UNIX time (seconds since 1970)
                t += incr # do offset
                t = time.localtime (t)
                year = t[0]
                month = t[1]
                day = t[2]
                self.display_date (day, month, year, s_len)
                return 1
            else:
                m = re.match ("([0-9]+)/([0-9]+)/([0-9]+)", s)
                if m:
                    day = int (m.group (1))
                    month = int (m.group (2))
                    year = int (m.group (3))
                    self.__data[self.headers[self.section][0]] = (day, month, year)
                    return 1
                else:
                    #wxMessageBox ("%s is not a valid date" % s, "Invalid entry", wxICON_ERROR | wxOK)
                    wxBell ()
                    return 0
        

    def display_date (self, day, month, year, s_len):
        self.ReplaceText (self.section_start, s_len, "%d/%d/%d" % (day, month, year))
        self.__data[self.headers[self.section][0]] = (day, month, year)

    def __selectionBad (self, start, end):
        for i in range (start, end):
            if self.GetStyleAt (i) in [STYLE_HEADER, STYLE_EMBED]:
                return 1
        return 0
    
    def Embed (self, text, clas, state):
	"""'text' is a embedded text created with a subclass of this widget defined
	by 'clas' and having other instance information in 'state'.
	it is used as a key in self.__embeds which stores child popup class and state
	information. Embed is only called once when the popup is first destroyed,
	so any duplicate keys refer to another popup; differentiate by adding a 
	number to the 'text' keyword
	"""
        n= 1
        ending = ''
        while self.__embeds.has_key (text + ending):
            n += 1
            ending = '#%d' % n
        state['__text'] = text+ending
        self.__embeds[text+ ending] = {'class':clas, 'state':state}
        self.ReplaceText (self.GetCurrentPos ()-self.replace_len, self.replace_len, text+ending, STYLE_EMBED, 1)
        self.GotoPos (self.GetCurrentPos ()+len (text+ending)+1)

    def Reembed (self, state):
        self.__embeds[state['__text']]['state'] = state

    def get_data (self):
        """
        Parses the contents and obtains the text by heading.
        If parsing fails (ie. the user has edited the headers
        despite my best efforts to prevent that) the whole
        widget text is returned under the key 'text'

        Extra fields used:
        __text: the label for this widget used in an embed
        __data: a dictionary by header label, for SELECTION types
        the backend ID returned by the match provider,
        None or not present if the user has made no selection
        (there still may be text under this heading, which
        should be used as a new value) For DATE a value as
        (day, month, year) triple may be present, for NUMBER
        a Python numeric object may be present

        @rtype: dictionary of strings
        @return: dictionary keyed by header name
        """
        r = re.compile (string.join ([h[0] for h in self.headers], ':(.*)') + ':(.*)', re.S)
        mo = r.match (self.GetText ())
        if not mo:
            gmLog.gmDefLog.Log (gmLog.lErr, "the SOAP structure has been corrupted")
            return {'text':self.GetText ()}
        else:
            ret = {}
            i = 1
            for hdr, type, matcher, poppers in self.headers:
                ret[hdr] = string.strip (mo.group (i))
                i += 1
            ret['__data'] = self.__data
            if self.__text:
                ret['__text'] = self.__text
            return ret

        
    def __keypressed (self, event):
	"""processes a KEY_DOWN event"""

	
        pos = self.GetCurrentPos ()

	"""on keypress, halt timer for autocompletion activation"""
	if self.timer:
            self.timer.Stop ()
            self.timer = None
	
	"""keypress in parent of popup will destroy the popup"""
        if self.__popup:
            self.__popup.Destroy ()
            self.__popup = None

	"""avoid state change checks if already waiting for a auto-completion selection"""    
        if self.AutoCompActive ():
            event.Skip ()
            return

    	
        hdr, typ, matcher, poppers = self.headers[self.section]

	"""read the conditional like a switch statement, each first level conditional
	is exclusive of others.
	"""
 	print 'Top or routine- current position is:' + str(pos)
	print event.KeyCode()
	#----------------------------------------------------------------------------------
	#if the key pressed was the return key i.e the enter key:
	#---------------------------------------------------------------------------------
        if event.KeyCode () == WXK_RETURN:
            print 'Hey, you pressed enter'
	    print self.GetCharAt(pos)
            if self.GetCharAt (pos) == 10 and not event.AltDown ():
                # we are at the end of a line  = Not correct=  this responds just to the enter key
                self.__cursorMoved (pos + 1)
		print 'are at end of line'
            elif self.GetStyleAt (pos) in  [STYLE_HEADER, STYLE_EMBED]:
                self.__cursorMoved (pos)
            else:
                if typ == TEXT:             #if user hits <enter key>
	            print 'here now'
		    if pos <> 0: #RT added
			self.InsertText (self.GetCurrentPos (), chr (10))
			self.GotoPos (self.GetCurrentPos ()+1)
        elif event.KeyCode () == WXK_F12:
            if self.popup:
                data = self.get_data ()
                if self.__we_are_new:
                    self.parent.Embed (self.GetSummary (data), self.__class__, data)
                else:
                    self.parent.Reembed (data)
                self.parent.SetFocus ()
                self.Destroy ()
            else:
                self.Process (self.get_data ())
        elif event.KeyCode () == WXK_LEFT:
	    print 'wxK_LEFT PRESSED'
            if pos > 0:
	        print 'cant go beyond start of the line'
                self.__cursorMoved (pos -1)
        elif event.KeyCode () == WXK_RIGHT:
            m = self.GetLength ()
            if pos < m:
                self.__cursorMoved (pos+1)
        elif event.KeyCode () == WXK_UP:
            line = self.LineFromPosition (pos)
            col = self.GetColumn (pos)
            if line > 0:
                line -= 1
                lineend = self.GetLineEndPosition (line)
                pos = self.PositionFromLine (line) + col
                if pos > lineend:
                    pos = lineend
                self.__cursorMoved (pos)
        elif event.KeyCode () == WXK_DOWN:  #downarrow key pressed
            line = self.LineFromPosition (pos)				#get current line number
	    print 'I\'ve pressed the down arrow key - am on line:' + str(line)
            col = self.GetColumn (pos)					#get current column number
            line += 1								#increment the line number
	    print 'Now you\'ve made line to be:' +str(line)
            pos = self.PositionFromLine (line) + col
            lineend  = self.GetLineEndPosition (line)
            if pos > lineend:
                pos = lineend
            self.__cursorMoved (pos)
        elif event.KeyCode () == WXK_ESCAPE:
            self.escape ()
        elif event.KeyCode () < 256 and not (event.ControlDown () and event.AltDown ()):
            # these are "text-damaging" events
            if event.KeyCode () == WXK_BACK and pos > 0:
                pos -= 1
            style = self.GetStyleAt (pos)
            if style == STYLE_HEADER:
                # this should never happen
                self.__cursorMoved (pos)
            elif style == STYLE_EMBED:
                # delete the embedded
                start, word = self.__get_word_by_style (pos, STYLE_EMBED)
                self.ReplaceText (start, len (word), '')
                if not event.KeyCode () in [WXK_DELETE, WXK_BACK]:
                    self.Skip ()
                del self.__embeds[word]
            else:
                if typ == NUMBER:
                    if chr(event.KeyCode ()) in '0123456789.,-+E\x08\x7F':
                        event.Skip ()
                elif typ == DATE:
                    if chr (event.KeyCode ()) in '0123456789/.-%s\x08\x7F' % _('dwmy').upper ():
                        event.Skip ()
                elif typ == SELECTION:
                    if self.__data.has_key (hdr):
                        del self.__data[hdr]
                    event.Skip ()
                else:
                    event.Skip ()
                if typ == TEXT or typ == SELECTION:
                    if chr (event.KeyCode ()) in string.letters:
                        start, word = self.__get_word_by_lex (pos)
                        word += chr (event.KeyCode ())
                        word = word.lower ()
                        if matcher:
                            flag, self.mlist = matcher.getMatches (word)
                            if flag:
                                self.replace_len = len (word)
                                self.__map_text_to_id = dict ([(i['label'], i['data']) for i in self.mlist])
                                self.UserListShow (1, string.join ([i['label'] for i in self.mlist], '\n'))
                        if poppers.has_key (word):
                            self.replace_len = len (word)
                            self.__pop (poppers[word], None)             
        else:
            # FIXME: need to provide for Undo, delete word, etc.
            pass

    def __cursorMoved (self, pos):
	"""processes a jump in text position. If the text position is within the range
	[section_start , max of (oldpos+1, current text length) ] then it is regarded
	as text entry into the current	section;
	otherwise it is a section jump. 
	"""
	print 'Am in the __cursorMoved routine'
	print 'Now I\'m on line:' + str(self.LineFromPosition(pos))
        oldpos = self.GetCurrentPos ()
        m = self.GetLength ()
        """moved_section flags a change in text section e.g. in SOAP, S section, O section..."""
	moved_section = pos < self.section_start or pos-oldpos > 1 or pos >= m

        hdr, typ, matcher, poppers = self.headers[self.section]

	"""if leaving a section, then validate the last section, 
	preventing jump to another section if the data doesn't succeed
	in basic type validation. 
	type is one of [NUMBER, DATE, TEXT, selection], see above package initializations
	"""
        if moved_section and typ == NUMBER:
            if not self.__validate_number ():
                self.GotoPos (oldpos)
                return
        if moved_section and typ == DATE:
            if not self.__validate_date ():
                self.GotoPos (oldpos)
                return

	"""if pos < GetLength(), which means cursor over existing text,
	then process re-editing of headers, embedded text, 
	and user list selections ( autocompletion).
	
	   if it is in the STYLE_HEADER header area, check the next position by
	   a recursive call to __cursorMoved() ( this function). 
	   
	   if it is in the STYLE_EMBED area (which marks popup created summary text)
	   then it is a re-edit of a previously embedded text:
	   go to either the start or end of the styled word under the cursor,
	   and call the popup associated with the embedded word.
	   The popup configuration for a word is stored in self.__embeds, keyed by
	   the word. The configuration is a map: 
	   the key 'class' stores the  SOAPTextCtrl subclass ,
	   and this is used to construct the popup within the self.__pop() function,
	   using this current control as the parent.

	   Finally, check for typing within a SELECTION area , and if moved into
	   such a section show the auto-completion  list
	
	if pos == GetLenth() and is a popup , then store the popup class and state.

	"""
        if pos < m:
            style = self.GetStyleAt (pos)
            if style == STYLE_HEADER:
                self.__cursorMoved (pos+1)
            elif style == STYLE_EMBED:
                start, word = self.__get_word_by_style (pos, STYLE_EMBED)
                if pos < start+len (word)-1:
                    self.GotoPos (start+len (word))
                else:
                    self.GotoPos (start)
                self.__pop (self.__embeds[word]['class'], self.__embeds[word]['state'])
            else:
                self.__calc_section (pos)
                hdr, typ, matcher, poppers = self.headers[self.section]
                self.GotoPos (pos)
                if typ == SELECTION and moved_section:
                    flag, self.mlist = matcher.getAllMatches ()
                    if flag:
                        self.replace_len = 0
                        self.__map_text_to_id = dict ([(i['label'], i['data']) for i in self.mlist])
                        self.UserListShow (1, string.join ([i['label'] for i in self.mlist], '\n'))
        else:
	    
            if self.popup:
                self.parent.SetFocus ()
                data = self.get_data ()
                if self.__we_are_new:
                    self.parent.Embed (self.GetSummary (data), self.__class__, data)
                else:
                    self.parent.Reembed (data)
                self.Destroy ()
                
    def __userlist (self, event):
        text = event.GetText ()
        hdr, typ, matchers, poppers = self.headers[self.section]
        if typ == TEXT:
            pos = self.GetCurrentPos ()
            start = pos - self.replace_len
        else:
            start = self.section_start
            pos = self.section_end
            self.__data[hdr] = self.__map_text_to_id[text]
        self.SetTargetEnd (pos)
        self.SetTargetStart (start)
        self.ReplaceTarget (text)
        self.StartStyling (start, 0xFF)
        self.SetStyling (len (text), STYLE_KEYWORD)
        self.__cursorMoved (start + len (text)+1)
        
    def __mouse_down (self, event):
        if self.AutoCompActive ():
            self.AutoCompCancel ()
        if self.__popup:
            self.__popup.Destroy ()
            self.__popup = None
        if self.timer:
            self.timer.Stop ()
            self.timer = None
        pos = self.PositionFromPoint (event.GetPosition ())
        self.__cursorMoved (pos)

    def escape (self):
        """
        Escape pressed
        Descendants may want to override this
        """
        if self.popup:
            self.parent.SetFocus ()
            self.Destroy ()
            

    def __pop (self, pclass, state):
            x, y = self.GetSizeTuple ()
            pos = self.PointFromPosition (self.GetCurrentPos ())
            x = x/4
            width = x*3
            height = y/2
            if pos.y > height:
                # cursor is in the bottom half of the window
                y = pos.y-height
            else:
                y = pos.y
            self.__popup = pclass (self, -1, wxPoint (x, y), wxSize (width, height), wxSIMPLE_BORDER)
            self.__popup.set_data (state)
            self.__popup.popup = 1
            self.__popup.Show ()
            self.__popup.SetFocus ()

### For testing only


class RecallCtrl (SOAPTextCtrl):
    def GetHeaders (self):
        return [('Reason', TEXT, None, {}),
                ('Date', DATE, None, {})]
    


    def GetSummary (self, data):
        return 'recall -- %s' % data['Reason']

class ScriptCtrl (SOAPTextCtrl):
    def GetHeaders (self):
        return [('Drug', TEXT, None, {}),
                ('Dose', DATE, None, {})]
		#('Instructions', TEXT ,None,{})]

    def GetSummary (self, data):
        return 'script -- %s' % data['Drug']

from Gnumed.pycommon.gmMatchProvider import cMatchProvider_FixedList

AOElist = [{'label':'otitis media', 'data':1, 'weight':1}, {'label':'otitis externa', 'data':2, 'weight':1},
            {'label':'cellulitis', 'data':3, 'weight':1}, {'label':'gingvitis', 'data':4, 'weight':1},
            {'label':'ganglion', 'data':5, 'weight':1}]

Subjlist = [{'label':'earache', 'data':1, 'weight':1}, {'label':'earache', 'data':1, 'weight':1},
           {'label':'ear discahrge', 'data':2, 'weight':1}, {'label':'eardrum bulging', 'data':3, 'weight':1},
           {'label':'sore arm', 'data':4, 'weight':1}, {'label':'sore tooth', 'data':5, 'weight':1}]

Planlist = [{'label':'pencillin V', 'data':1, 'weight':1}, {'label':'penicillin X', 'data':2, 'weight':1},
            {'label':'penicillinamine', 'data':3, 'weight':1}, {'label':'penthrane', 'data':4, 'weight':1},
            {'label':'penthidine', 'data':5, 'weight':1}]

class MySOAPCtrl (SOAPTextCtrl):
    def GetHeaders (self):
        return [
            (_('Subjective'), TEXT, cMatchProvider_FixedList (Subjlist), {}),
            (_('Objective'), TEXT, None, {}),
            (_('Assessment'), SELECTION, cMatchProvider_FixedList (AOElist), {}),
            (_('Plan'), TEXT, cMatchProvider_FixedList (Planlist), {'recall':RecallCtrl}) #,{'script':ScriptCtrl})
            ]



class testFrame(wxFrame):
    def __init__(self, title):
        # begin wxGlade: MyFrame.__init__
        wxFrame.__init__(self, None, wxNewId (), title)
        self.text_ctrl_1 = MySOAPCtrl(self, -1)
        self.text_ctrl_1.set_data ({'Subjective':'earache', 'Assessment':'otitis media'})
        EVT_CLOSE (self, self.OnClose)

        self.__do_layout()
        # end wxGlade

    def __do_layout(self):
        # begin wxGlade: MyFrame.__do_layout
        sizer_1 = wxBoxSizer(wxVERTICAL)
        sizer_1.Add(self.text_ctrl_1, 1, wxEXPAND, 0)
	#self.text_ctrl_1.SetFont(
        self.SetAutoLayout(1)
        self.SetSizer(sizer_1)
        sizer_1.Fit(self)
       # sizer_1.SetSizeHints(self)
        #self.Layout()
        # end wxGlade

    def OnClose (self, event):
        print self.text_ctrl_1.get_data ()
        self.Destroy ()

# end of class MyFrame


class testApp (wxApp):
    def OnInit (self):
        self.frame = testFrame ("Test SOAP")
        self.frame.Show ()
        return 1

if __name__ == '__main__':
    app = testApp (0)
    app.MainLoop ()
_______________________________________________
Gnumed-devel mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/gnumed-devel

Reply via email to