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