[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
gnue/gnuef TODO samples/po/sc_po_entry.gfd src/...
From: |
James Thompson |
Subject: |
gnue/gnuef TODO samples/po/sc_po_entry.gfd src/... |
Date: |
Wed, 20 Jun 2001 14:43:17 -0700 |
CVSROOT: /cvs
Module name: gnue
Changes by: James Thompson <address@hidden> 01/06/20 14:43:16
Modified files:
gnuef : TODO
gnuef/samples/po: sc_po_entry.gfd
gnuef/src : GFClient.py GFForm.py GFInstance.py GFParser.py
UIbase.py UIwxpython.py
Log message:
Added tabbed form support
CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnuef/TODO.diff?cvsroot=OldCVS&tr1=1.52&tr2=1.53&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnuef/samples/po/sc_po_entry.gfd.diff?cvsroot=OldCVS&tr1=1.5&tr2=1.6&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnuef/src/GFClient.py.diff?cvsroot=OldCVS&tr1=1.20&tr2=1.21&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnuef/src/GFForm.py.diff?cvsroot=OldCVS&tr1=1.102&tr2=1.103&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnuef/src/GFInstance.py.diff?cvsroot=OldCVS&tr1=1.10&tr2=1.11&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnuef/src/GFParser.py.diff?cvsroot=OldCVS&tr1=1.34&tr2=1.35&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnuef/src/UIbase.py.diff?cvsroot=OldCVS&tr1=1.38&tr2=1.39&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/gnue/gnuef/src/UIwxpython.py.diff?cvsroot=OldCVS&tr1=1.95&tr2=1.96&r1=text&r2=text
Patches:
Index: gnue/gnuef/TODO
diff -u gnue/gnuef/TODO:1.52 gnue/gnuef/TODO:1.53
--- gnue/gnuef/TODO:1.52 Wed Jun 6 18:46:53 2001
+++ gnue/gnuef/TODO Wed Jun 20 14:43:16 2001
@@ -88,7 +88,8 @@
Make other datasources accessible from forms easily
-
+Features
+ Goto record shortcut
Index: gnue/gnuef/samples/po/sc_po_entry.gfd
diff -u gnue/gnuef/samples/po/sc_po_entry.gfd:1.5
gnue/gnuef/samples/po/sc_po_entry.gfd:1.6
--- gnue/gnuef/samples/po/sc_po_entry.gfd:1.5 Thu Jun 7 18:36:52 2001
+++ gnue/gnuef/samples/po/sc_po_entry.gfd Wed Jun 20 14:43:16 2001
@@ -1,11 +1,11 @@
<?xml version="1.0" ?>
-<form>
+<form tabbed="">
<options>
<title>GNUe Supply Chain : Purchase Order Entry</title>
<version>0.0.2</version>
- <height>23</height>
+ <height>24</height>
<width>80</width>
</options>
@@ -63,7 +63,7 @@
- <page>
+ <page name="Customer Info">
<block name="blckPO" datasource="dtsrcPOInfo">
<label text="PO Number" x="1" y="1"/>
<entry name="ntryPONum" field="po_number" x="1" y="2" width="16" />
@@ -134,7 +134,7 @@
</page>
- <page>
+ <page name="Item info">
<block name="blckPOItem" datasource="dtsrcPOItem">
<label text="Item Number" x="1" y="1"/>
<label text="Description" x="17" y="1"/>
Index: gnue/gnuef/src/GFClient.py
diff -u gnue/gnuef/src/GFClient.py:1.20 gnue/gnuef/src/GFClient.py:1.21
--- gnue/gnuef/src/GFClient.py:1.20 Wed Jun 6 18:46:53 2001
+++ gnue/gnuef/src/GFClient.py Wed Jun 20 14:43:16 2001
@@ -34,7 +34,7 @@
#
# Copyright (c) 2000 Free Software Foundation
#
-# $Id: GFClient.py,v 1.20 2001/06/07 01:46:53 jamest Exp $
+# $Id: GFClient.py,v 1.21 2001/06/20 21:43:16 jamest Exp $
#
import pstats
@@ -97,7 +97,10 @@
try:
formfile = self.ARGUMENTS[0]
except:
- self.handleStartupError ("No Forms Definition File Specified.")
+ if sys.argv[0][-11:] != 'GFClient.py':
+ formfile =
GConfig.get('FormDir')+"/"+os.path.basename(sys.argv[0])+".gfd"
+ else:
+ self.handleStartupError ("No Forms Definition File Specified.")
# Initialize user interface (defaults to gui)
Index: gnue/gnuef/src/GFForm.py
diff -u gnue/gnuef/src/GFForm.py:1.102 gnue/gnuef/src/GFForm.py:1.103
--- gnue/gnuef/src/GFForm.py:1.102 Mon Jun 18 03:02:23 2001
+++ gnue/gnuef/src/GFForm.py Wed Jun 20 14:43:16 2001
@@ -707,6 +707,21 @@
self._currentPage = pageWidget
+ def gotoPage(self, index):
+ for object in self._blockList:
+ pageWidget = object
+ while pageWidget.getObjectType() != 'GFPage':
+ pageWidget = pageWidget._parent
+
+ if self._pageList[index] == pageWidget:
+ self._currentPage = self._pageList[index]
+ self._currentBlock = object
+ break
+
+ # reset current entry
+ self._currentEntry = None
+ self._currentBlock.walk(self.setInitialFocus)
+
def prevRecord(self):
for block in self._blockList:
if hasattr(block,'master'):
Index: gnue/gnuef/src/GFInstance.py
diff -u gnue/gnuef/src/GFInstance.py:1.10 gnue/gnuef/src/GFInstance.py:1.11
--- gnue/gnuef/src/GFInstance.py:1.10 Sun Jun 17 11:46:59 2001
+++ gnue/gnuef/src/GFInstance.py Wed Jun 20 14:43:16 2001
@@ -34,7 +34,7 @@
#
# Copyright (c) 2000 Free Software Foundation
#
-# $Id: GFInstance.py,v 1.10 2001/06/17 18:46:59 dneighbors Exp $
+# $Id: GFInstance.py,v 1.11 2001/06/20 21:43:16 jamest Exp $
#
import pstats
@@ -74,6 +74,7 @@
'requestPREVRECORD' : self.prevRecord,
'requestNEXTRECORD' : self.nextRecord,
'requestJUMPRECORD' : self.jumpRecords,
+ 'requestPAGE' : self.gotoPage,
'requestKEYPRESS' : self.keyPress,
'requestREPLACEVALUE' : self.replaceValue,
@@ -162,7 +163,7 @@
self.dispatchEvent(GFEvent('gotoENTRY',{'object':self._form._currentEntry}))
self.updateStatus()
-
+
#
# previousBlock
#
@@ -175,6 +176,16 @@
self.dispatchEvent(GFEvent('gotoENTRY',{'object':self._form._currentEntry}))
self.updateStatus()
+ #
+ # gotoPage
+ #
+ # Called to make the form jump to a specific page
+ #
+ def gotoPage(self,event):
+ self._form.gotoPage(event.data)
+ self.dispatchEvent(GFEvent('gotoPAGE',self._form._currentPage));
+ self.updateStatus()
+
#
# previousRecord
#
Index: gnue/gnuef/src/GFParser.py
diff -u gnue/gnuef/src/GFParser.py:1.34 gnue/gnuef/src/GFParser.py:1.35
--- gnue/gnuef/src/GFParser.py:1.34 Wed Jun 20 12:58:20 2001
+++ gnue/gnuef/src/GFParser.py Wed Jun 20 14:43:16 2001
@@ -68,7 +68,8 @@
xmlElements = {
'form': ( GFForm.GFForm,
{ 'title': (0, 0, char, None),
- 'readonly': (0, 0, bool, 0 )},
+ 'readonly': (0, 0, bool, 0 ),
+ 'tabbed': (0, 0, char, None)},
1, (0,None)),
'import': ( GFLibrary.GFImport,
{ 'library': (1, 0, char, None),
Index: gnue/gnuef/src/UIbase.py
diff -u gnue/gnuef/src/UIbase.py:1.38 gnue/gnuef/src/UIbase.py:1.39
--- gnue/gnuef/src/UIbase.py:1.38 Sun Jun 10 22:16:27 2001
+++ gnue/gnuef/src/UIbase.py Wed Jun 20 14:43:16 2001
@@ -68,7 +68,13 @@
global UI
UI = __import__(self.getModule(), globals(), locals(), ['UIAbout'])
- self.widgets = UI.WIDGETS
+ self.widgets = {'GFLabel' : UI.UILabel,
+ 'GFBox' : UI.UIBox,
+ 'GFPage' : UI.UIPage,
+ 'GFForm' : UI.UIForm,
+ 'GFEntry' : UI.UIEntry,
+ 'GFButton' : UI.UIButton,
+ 'GFScrollBar' : UI.UIScrollBar}
self._loginHandler = None
@@ -350,7 +356,7 @@
#
class UIWidget:
- def __init__(self, object, container, textWidth, textHeight, widgetWidth,
widgetHeight, interface, initialize=1):
+ def __init__(self, object, container, textWidth, textHeight, widgetWidth,
widgetHeight, interface):
self.widgets = []
if not hasattr(object,'visibleCount'):
@@ -372,10 +378,10 @@
if not object.hidden:
for spacer in range(int(object.visibleCount)):
- newWidget = self.createWidget(object, container, textWidth,
textHeight, widgetWidth, widgetHeight, interface, spacer, initialize)
+ newWidget = self.createWidget(object, container, textWidth,
textHeight, widgetWidth, widgetHeight, interface, spacer)
self.widgets.append(newWidget)
- def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight, interface, spacer,initialize=1):
+ def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight, interface, spacer):
GDebug.printMesg(1,"UI doesn't support %s" % self.__class__)
Index: gnue/gnuef/src/UIwxpython.py
diff -u gnue/gnuef/src/UIwxpython.py:1.95 gnue/gnuef/src/UIwxpython.py:1.96
--- gnue/gnuef/src/UIwxpython.py:1.95 Tue Jun 19 13:35:52 2001
+++ gnue/gnuef/src/UIwxpython.py Wed Jun 20 14:43:16 2001
@@ -39,6 +39,10 @@
from gnue.common import GDebug, GLoginHandler
from gnue.common import GConfig
+
+_NOTEBOOK = None
+_LOOPTRAP = 0
+
#
# Little global helper routine to set font according to options
#
@@ -135,7 +139,7 @@
#
if not self._disableSplash:
self.splash =
SplashScreen(None,bitmapfile=GConfig.get('splashScreenPNG'),
- # duration=65535, callback=self.onMain,
+ # duration=1, # callback=self.onMain,
style=wxSIMPLE_BORDER|wxCENTRE_ON_SCREEN )
swidth,sheight = self.splash.GetSizeTuple()
@@ -272,9 +276,11 @@
self.mainWindow.panel = wxPanel(self.mainWindow,-1,
wxDefaultPosition,self.mainWindow.GetSize())
+ #self.mainWindow.panel = None
EVT_CHAR(self.mainWindow.panel, self.uiEventTrap)
self.currentWidget = [self.mainWindow.panel]
+ #self.currentWidget = [self.mainWindow]
self.SetTopWindow(self.mainWindow)
EVT_CLOSE(self.mainWindow,self.closeTrap)
@@ -293,6 +299,7 @@
self.mainWindow.panel = self._pageList[0]
self.mainWindow.panel.SetSize(wxSize(width*int(self.widgetWidth),
int(height+self.menu_sb_space)*int(self.widgetHeight)))
+
self._pageList[0].Show(TRUE)
self.dispatchEvent(GFEvent('requestPREVRECORD'))
self.dispatchEvent(GFEvent('requestNEXTRECORD'))
@@ -300,7 +307,16 @@
# Only one page at a time can be visible
self.visiblePage = self._pageList[0]
-
+ if _NOTEBOOK: # Adjust sizes
+ #self.mainWindow.SetSize(wxSize(width*int(self.widgetWidth)+10,
+ #
int(height+self.menu_sb_space)*int(self.widgetHeight)))
+ #self.mainWindow.panel.SetSize(wxSize(width*int(self.widgetWidth)+10,
+ #
int(height+self.menu_sb_space)*int(self.widgetHeight)))
+ _NOTEBOOK.SetSize(wxSize(width*int(self.widgetWidth),
+
int(height+self.menu_sb_space)*int(self.widgetHeight)))
+ #print self.mainWindow.GetSize()
+ #print self.mainWindow.panel.GetSize()
+ #print _NOTEBOOK.GetSize()
#############################################################################
#
@@ -373,13 +389,20 @@
#
def gotoPage(self, event):
index = self._formToUI[event.data][1]
- self.visiblePage.Show(FALSE)
- self._formToUI[event.data][0][index].Show(TRUE)
- self.visiblePage = self._formToUI[event.data][0][index]
+ if not _NOTEBOOK:
+ self.visiblePage.Show(FALSE)
+ self.visiblePage = self._formToUI[event.data][0][index]
+
self.visiblePage.SetSize(wxSize(int(self._form.getOption('width'))*int(self.widgetWidth),
+
int(int(self._form.getOption('height'))+self.menu_sb_space)*int(self.widgetHeight)))
+ else:
+ self.visiblePage = self._formToUI[event.data][0][index]
+ for count in range(_NOTEBOOK.GetPageCount()):
+ if self.visiblePage.GetId() == _NOTEBOOK.GetPage(count).GetId():
+ _NOTEBOOK.SetSelection(count)
+ break
+
self.visiblePage.Show(TRUE)
-
self.visiblePage.SetSize(wxSize(int(self._form.getOption('width'))*int(self.widgetWidth),
-
int(int(self._form.getOption('height'))+self.menu_sb_space)*int(self.widgetHeight)))
#
# formAlert
@@ -542,7 +565,19 @@
for count in range(len(self._formToUI[key][0])):
if self._formToUI[key][0][count].GetId() == object.GetId():
action = GFEvent('fireTRIGGER',key._trigger)
+
+ #
+ # Notebook tab events
+ #
+ elif event.GetEventType() == wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING:
+ global _LOOPTRAP
+ if _LOOPTRAP == 0:
+ _LOOPTRAP = 1
+ action = GFEvent('requestPAGE',event.GetSelection())
+ else:
+ _LOOPTRAP = 0
+
#
# Unhandled events
#
@@ -583,7 +618,7 @@
self.textctrlList = []
- messageField = wxStaticText(self.dlg, 1010, str(loginMesg))
+ messageField = wxStaticText(self.dlg, 1010, loginMesg)
labelList = []
dlgWidth = getLargest(bmp.GetWidth(), messageField.GetSize().GetWidth()+20)
@@ -756,7 +791,7 @@
# Widget set specific function that creates a single instance of a label
#
class UILabel(UIWidget, UIHelper):
- def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer,initialize=1):
+ def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer):
style = wxALIGN_LEFT|wxST_NO_AUTORESIZE
if hasattr(object,'alignment'):
@@ -770,6 +805,7 @@
(int(object.y)+spacer+(spacer*object.gap))*int(widgetHeight)),
wxSize(self.itemWidth,self.itemHeight), style)
initFont(newWidget)
+# newWidget.Show(FALSE)
return newWidget
#
@@ -778,13 +814,14 @@
# Widget set specific function that creates a single instance of a border box
#
class UIBox(UIWidget, UIHelper):
- def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer,initialize=1):
+ def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer):
newWidget = wxStaticBox(container,-1,str(object.label),
wxPoint(int(object.x)*int(widgetWidth)+(int(widgetWidth)/2),
(int(object.y)+spacer)*int(widgetHeight)+(int(widgetHeight)/2)),
wxSize(int(object.width)*int(widgetWidth)-(int(widgetWidth)/2),
int(object.height)*int(widgetHeight)-(int(widgetHeight)/2)))
initFont(newWidget)
+ # newWidget.Show(FALSE)
return newWidget
#
@@ -794,12 +831,13 @@
# to navigate multiple records
#
class UIScrollBar(UIWidget, UIHelper):
- def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer,initialize=1):
+ def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer):
newWidget =wxScrollBar(container,-1,
wxPoint(int(object.x)*int(widgetWidth),(int(object.y)+spacer)*int(widgetHeight)),
wxSize(int(object.width)*int(widgetWidth),int(object.height)*int(widgetHeight)),
wxSB_VERTICAL)
initFont(newWidget)
+ # newWidget.Show(FALSE)
return newWidget
#
# UIButton
@@ -807,15 +845,15 @@
# Widget set specific function that creates a single instance of a button
#
class UIButton(UIWidget, UIHelper):
- def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer,initialize=1):
+ def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer):
newWidget = wxButton(container,-1,str(object.label),
wxPoint(int(object.x)*int(widgetWidth),(int(object.y)+spacer)*int(widgetHeight)),
wxSize(int(object.width)*int(widgetWidth),int(object.height)*int(widgetHeight))
)
initFont(newWidget)
- if initialize:
- EVT_BUTTON(newWidget,newWidget.GetId(),interface.uiEventTrap)
+ EVT_BUTTON(newWidget,newWidget.GetId(),interface.uiEventTrap)
+# newWidget.Show(FALSE)
return newWidget
#
@@ -824,12 +862,17 @@
# Widget set specific function that creates a single instance of a page
#
class UIPage(UIWidget, UIHelper):
- def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer,initialize=1):
- newWidget = wxPanel(container, -1,wxDefaultPosition,container.GetSize())
- newWidget.Show(FALSE)
+ def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer):
+
+ if _NOTEBOOK:
+ newWidget = wxPanel(_NOTEBOOK, -1,wxDefaultPosition,_NOTEBOOK.GetSize())
+ _NOTEBOOK.AddPage(newWidget,object.name)
+ newWidget.Show(TRUE)
+ else:
+ newWidget = wxPanel(container, -1,wxDefaultPosition,container.GetSize())
+ newWidget.Show(FALSE)
- if initialize:
- EVT_CHAR(newWidget, interface.uiEventTrap)
+ EVT_CHAR(newWidget, interface.uiEventTrap)
initFont(newWidget)
interface._pageList.append(newWidget)
return newWidget
@@ -840,7 +883,7 @@
# Widget set specific function that creates a single instance of a data entry
widget
#
class UIEntry(UIWidget, UIHelper):
- def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer,initialize=1):
+ def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer):
if hasattr(object,'style'):
style = object.style
else:
@@ -848,11 +891,10 @@
if style == 'dropdown':
choices = []
- if initialize:
- values = object.allowedValues()
- for key in values.keys():
- choices.append(values[key])
- choices.sort()
+ values = object.allowedValues()
+ for key in values.keys():
+ choices.append(values[key])
+ choices.sort()
newWidget = wxComboBox(container, -1, "",
wxPoint(int(object.x)*int(widgetWidth),
@@ -862,9 +904,8 @@
choices, wxCB_DROPDOWN)
newWidget.SetValue("")
- if initialize:
- EVT_CHAR(newWidget, interface.uiEventTrap)
- EVT_COMBOBOX(newWidget, newWidget.GetId(), interface.uiEventTrap)
+ EVT_CHAR(newWidget, interface.uiEventTrap)
+ EVT_COMBOBOX(newWidget, newWidget.GetId(), interface.uiEventTrap)
elif style == 'checkbox':
style = object.style
@@ -876,18 +917,13 @@
# wxSize(int(object.width)*int(self.textWidth),
#
int(object.height)*int(self.textHeight)), wxNO_BORDER)
newWidget.SetValue(0)
-
- if initialize:
- EVT_CHECKBOX(newWidget, newWidget.GetId(), interface.uiEventTrap)
+ EVT_CHECKBOX(newWidget, newWidget.GetId(), interface.uiEventTrap)
else:
- if initialize:
- styles = wxTE_PROCESS_TAB
- if int(object.height) > 1:
- styles = styles|wxTE_MULTILINE
- else:
- styles = 0
+ styles = wxTE_PROCESS_TAB
+ if int(object.height) > 1:
+ styles = styles|wxTE_MULTILINE
newWidget = wxTextCtrl(container, -1, object._value,
wxPoint(int(object.x)*int(widgetWidth),
@@ -895,11 +931,11 @@
wxSize(int(object.width)*int(textWidth),
int(object.height)*int(textHeight)+1),
styles)
- if initialize:
- EVT_CHAR(newWidget, interface.uiEventTrap)
- EVT_MOUSE_EVENTS(newWidget, interface.uiEventTrap)
+ EVT_CHAR(newWidget, interface.uiEventTrap)
+ EVT_MOUSE_EVENTS(newWidget, interface.uiEventTrap)
initFont(newWidget)
+# newWidget.Show(FALSE)
return newWidget
#
@@ -908,11 +944,31 @@
# Widget set specific function that creates a single instance of a Form widget
#
class UIForm(UIWidget, UIHelper):
- def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer,initialize=1):
- newWidget = wxPanel(interface.mainWindow.panel,-1, wxDefaultPosition)
- if initialize:
- EVT_CLOSE(interface.mainWindow,interface.closeTrap)
-
+ def createWidget(self, object, container, textWidth, textHeight,
widgetWidth, widgetHeight,interface,spacer):
+ global _NOTEBOOK
+
+ if object.tabbed:
+ print object.tabbed
+ if object.tabbed == 'left':
+ tabstyle = wxNB_LEFT
+ elif object.tabbed == 'right':
+ tabstyle = wxNB_RIGHT
+ elif object.tabbed == 'bottom':
+ tabstyle = wxNB_BOTTOM
+ else:
+ tabstyle = 0
+
+ _NOTEBOOK =
wxNotebook(container,-1,wxPoint(10,10),size=container.GetSize(),style=tabstyle)
+ newWidget = _NOTEBOOK
+ _NOTEBOOK.Show(TRUE)
+ EVT_NOTEBOOK_PAGE_CHANGING(newWidget, newWidget.GetId(),
interface.uiEventTrap)
+
+ else:
+ newWidget = wxPanel(interface.mainWindow.panel,-1,
wxDefaultPosition,size=container.GetSize())
+
+ EVT_CLOSE(interface.mainWindow,interface.closeTrap)
+
+ newWidget.Show(TRUE)
return newWidget
#
@@ -969,12 +1025,9 @@
raise GLoginHandler.UserCanceledLogin
+
+
+
+
-WIDGETS = {'GFLabel' : UILabel,
- 'GFBox' : UIBox,
- 'GFPage' : UIPage,
- 'GFForm' : UIForm,
- 'GFEntry' : UIEntry,
- 'GFButton' : UIButton,
- 'GFScrollBar' : UIScrollBar}
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- gnue/gnuef TODO samples/po/sc_po_entry.gfd src/...,
James Thompson <=