rexx-things/modules/windows/oodialog/userGuide/exercises/Exercise08/Order/OrderFormView.rex
2025-03-12 20:50:48 +00:00

954 lines
40 KiB
Rexx
Executable File

/*----------------------------------------------------------------------------*/
/* */
/* Copyright (c) 2011-2014 Rexx Language Association. All rights reserved. */
/* */
/* This program and the accompanying materials are made available under */
/* the terms of the Common Public License v1.0 which accompanies this */
/* distribution. A copy is also available at the following address: */
/* https://www.oorexx.org/license.html */
/* */
/* Redistribution and use in source and binary forms, with or */
/* without modification, are permitted provided that the following */
/* conditions are met: */
/* */
/* Redistributions of source code must retain the above copyright */
/* notice, this list of conditions and the following disclaimer. */
/* Redistributions in binary form must reproduce the above copyright */
/* notice, this list of conditions and the following disclaimer in */
/* the documentation and/or other materials provided with the distribution. */
/* */
/* Neither the name of Rexx Language Association nor the names */
/* of its contributors may be used to endorse or promote products */
/* derived from this software without specific prior written permission. */
/* */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
/* */
/*----------------------------------------------------------------------------*/
/* ooDialog User Guide
Exercise 08: The OrderFormView class v03-01 06Jun13
OrderFormView.rex
Contains: class "OrderFormView", class "HRSofv".
Pre-requisite files: OrderFormView.rc, OrderFormView.h.
Changes:
v01-00 07Jun12: First version.
v02-00 08Jan13: OrderFormView Modified to use the Model-View Framework (MVF).
Removed stand-alone startup (not now needed).
25Feb13: Added control dialogs in tab sheet.
27Feb13: Made Order Date functional.
01Apr13: After ooDialog 4.2.2, Support folder moved to exercise
folder, so change to ::Requires needed.
v03-00 27Apr13: Add ability to populate Order with Customer Details and
Order Lines.
25May13: Now inherits directly from RcDialog plus the View &
Component mixins.
v03-01 06Jun13: Added drag/drop code (method 'dmDrop') to make
OrderFormView a target. Also added code to the Customer
Details control dialog so that Customer can be provided by
drag/drop or by entering Cutomer Number.
------------------------------------------------------------------------------*/
.Application~addToConstDir("Order\OrderFormView.h")
::REQUIRES "ooDialog.cls"
::REQUIRES "support\View.rex" -- v03
/*==============================================================================
OrderFormView v02-01 06Jun13
-------------
The "view" (or "gui") Data Entry part of the Sales Order component.
Changes:
v01-00 07Jun12: First Version
v02-00 05Oct12: Modified to use the Model-View Framework (MVF) including
removal of stand-alone startup.
27Feb13: Changed to show tabs (control dialogs).
Corrected the Order Date control and limited order date to
one year ahead.
Commented-out say's.
20May13: Now inherits directly from RcDialog plus the View & Component mixins
v02-01 06Jun13: Added drag/drop code to make OrderFormView a target.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
--::CLASS OrderFormView SUBCLASS RcView PUBLIC
::CLASS OrderFormView SUBCLASS RcDialog PUBLIC INHERIT View Component -- v03
::ATTRIBUTE tabContent
::ATTRIBUTE orderTotals
::METHOD newInstance CLASS PUBLIC
use strict arg idModel, rootDlg
--say; say ".OrderFormView-newInstance: rootDlg =" rootDlg
dlg = self~new("Order\OrderFormView.rc", "IDD_ORDFORM_DIALOG")
dlg~activate(idModel, rootDlg)
return dlg
/*----------------------------------------------------------------------------
Dialog Setup Methods
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD init
-- creates the dialog instance but does not make it visible.
expose menuBar
--say "OrderFormView-init-01"
forward class (super) continue
self~initView
if \ self~createMenuBar then do -- if there was a problem
self~initCode = 1
return
end
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD createMenuBar
-- Creates the menu bar on the dialog.
expose menuBar
--say "OrderFormView-createMenuBar-01"
menuBar = .ScriptMenuBar~new("Order\OrderFormView.rc", IDR_ORDFORM_MENU, , , .true)
return .true
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD activate unguarded
expose rootDlg idModelInstance orderData cd1 cd2 orderTotal custDiscount -
taxRate eventMgr
use strict arg idModelInstance, rootDlg
forward class (super) continue
orderData = RESULT
-- set up tabs for Customer Details and Order Lines:
cd1 = .CustomerDetailsDlg~new("Order\OrderFormView.rc", IDD_ORDFORM_CUST_DIALOG)
cd2 = .OrderLinesDlg~new("Order\OrderFormView.rc", IDD_ORDFORM_ORDLINES_DIALOG)
tabContent = .array~of(cd1, cd2)
--say "OrderFormView-activate-01: tabContent =" tabContent[1]||"," tabContent[2]
cd1~ownerDialog = self
cd2~ownerDialog = self
self~prep(tabContent)
-- Send OrderFormView dlg id to the two Control Dialogs so that they can
-- communicate with OrderFormView.
cd1~setOrderFormDlg(self)
cd2~setOrderFormDlg(self)
cd2~rootDialog(rootDlg) -- Tell cd2 what the root dialog is.
-- Set up Order Totals and initialise CustDiscount:
orderTotal = 0
--orderTotals = .OrderTotals~new
custDiscount = 0 -- Default customer discount
taxRate = 0.05 -- 5% tax on discounted order total
-- Tell EventMgr that we want to know when app closes:
--eventMgr = .local~my.EventMgr
--r = eventMgr~registerInterest("appClosing",self)
self~registerInterest("appClosing",self)
--say "OrderFormView-activate-03: eventMgr response =" r
self~popUpAsChild(rootDlg,"SHOWTOP",,"IDI_ORDFORM_DLGICON")
--say "OrderFormView-activate-04."
return
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD initDialog
-- Called by ooDialog after SHOWTOP.
expose menuBar ecOrderNo orderData tabContent tabControl orderDate -
stCost stDisc stDiscCost stTax stTot orderTotals controlDialogsClosed
--say "OrderFormView-initDialog-01"
menuBar~attachTo(self)
-- Tab stuff starts:
cd1 = tabContent[1]
cd2 = tabContent[2]
cd1~execute
cd2~execute
-- Add the tabs to the tab control.
tabControl = self~newTab(IDC_ORDFORM_TABS)
tabControl~addSequence("Customer Details", "Order Lines")
-- tab stuff ends
ecOrderNo = self~newEdit("IDC_ORDFORM_ORDNO")
--say "OrderFormView-initDialog-02: ecOrderNo =" ecOrderNo
btnCancelOrder = self~newPushButton("IDC_CANCEL")
btnPlaceOrder = self~newPushButton("IDC_ORDFORM_PLACEORDER")
self~connectButtonEvent("IDC_CANCEL","CLICKED",cancel)
self~connectButtonEvent("IDC_ORDFORM_PLACEORDER","CLICKED",placeOrderBtn)
-- Get proxy for Order date and set its format. By default, it shows today.
--Also, set allowable date range selected to between today and 1 year's time.
orderDate = self~newDateTimePicker(IDC_ORDFORM_DATE);
orderDate~setFormat("MMM dd',' yyyy")
today = .DateTime~today
maxOrderDate = today~addYears(1)
orderDate~setRange(.array~of(today,maxOrderDate))
-- Get proxies for Order Total Amounts:
stCost = self~newStatic("IDC_ORDFORM_TOTCOST")
stDisc = self~newStatic("IDC_ORDFORM_TOTDISC")
stDiscCost = self~newStatic("IDC_ORDFORM_TOTDISCCOST")
stTax = self~newStatic("IDC_ORDFORM_TOTTAX")
stTot = self~newStatic("IDC_ORDFORM_ORDTOT")
ecOrderNo~setText(orderData[formNumber])
-- Tab stuff starts:
-- Determine the position and size of the display area of the tab control.
self~calculateDisplayArea
-- Position and show the control dialog used for the first page of the tab.
self~positionAndShow(1)
-- tab stuff ends
controlDialogsClosed = .false
/*
Following did not work - it gave Cust Details on both tabs!!
cd2 = tabContent[2]
say "***** cd2 =" cd2
cd2~ownerDialog = self -- trial 21:45
cd2~execute
*/
-- Set as target for Drag/Drop:
self~dmSetAsTarget:super()
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-- This method not used - message goes to the class. Left in just for the
-- time being. Delete when all drag/drop OK.
--::METHOD dmQueryDrop
--use strict arg sourceDlg, mousePos -- try also without mousepos.
--say "OrderFormView-dmQueryDrop-01."
--return .true
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD dmDrop PUBLIC
expose cd1 cd2
use strict arg sourceModel, sourceDlg
--say "OrderFormView-dmDrop-01; sourceModel, sourceDlg =" sourceModel||"," sourceDlg
--say "OrderFormView-dmDrop-02: cd1, cd2 =" cd1||"," cd2
parse var sourceModel . modelName
select
when modelName = "CUSTOMERMODEL" then do
cd1~getCustomer(sourceModel); return .true
end
when modelName = "PRODUCTMODEL" then do
--say "OrderFormView-dmDrop-03: Product dropped.";
cd2~getProduct(sourceModel); return .true
end
end
return .false
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD showTotals PUBLIC
expose custDiscount taxRate stCost stDisc stDiscCost stTax stTot orderTotal
use arg orderLineAmount
--if custDiscount = "CUSTDISCOUNT" then custDiscount = 0 -- If user enters products first.
--say "OrderFormView-showTotals-01: custDiscount, orderLineAmount =" custDiscount orderLineAmount
orderTotal = orderTotal + orderLineAmount
discount = (orderTotal * custDiscount)~format(,0)
--say "OrderFormView-showTotals-01: discount =" discount
discountedTotal = orderTotal - discount
tax = (discountedTotal * taxRate)~format(,0)
finalTotal = discountedTotal + tax
--say "OrderFormView-showTotals-02: discount / tax =" discount||" / "||tax
-- Format numbers from nnnnn to nnn.nn for display:
x = myFormat(orderTotal); --say "OrderFormView-showTotals-03:" x
stCost~setText(myFormat(orderTotal))
--stCost~setText( (orderTotal/100)~format(,2))
stDisc~setText(myFormat(discount))
--if discount = 0 then do; stDisc~setText("0.00"); end
--else do; stDisc~setText((discount/100)~format(,2)); end
stDiscCost~setText(myFormat(discountedTotal))
--stDiscCost~setText( (discountedTotal/100)~format(,2))
stTax~setText(myFormat(tax))
--stTax~setText( (tax/100)~format(,2))
stTot~setText(myFormat(finalTotal))
--stTot~setText( (finalTotal/100)~format(,2))
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD setCustDiscount
expose custDiscount
use arg custDiscount
--say "OrderFormView-setDustDiscount-01: discount =" custDiscount
-- Use only first character - A, B or C:
code = custDiscount~left(1)
select
when code = "A" then custDiscount = 0.15 -- 15% discount
when code = "B" then custDiscount = 0.1 -- 10% discount
when code = "C" then custDiscount = 0.05 -- 5% discount
otherwise custDiscount = 0
end
--say "OrderFormView-setDustDiscount-01: discount =" custDiscount
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
--::METHOD updateTotals
/*----------------------------------------------------------------------------
Event-Handler Methods - Button Events
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD placeOrderBtn UNGUARDED
ret = MessageDialog(.HRSofv~NoBtn, self~hwnd, "Place Order Button", 'WARNING')
/*----------------------------------------------------------------------------
Event-Handler Methods - Menu Events
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD placeOrder UNGUARDED
self~noMenuFunction(.HRSofv~PlaceOrder)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD saveOrder UNGUARDED
self~noMenuFunction(.HRSofv~SaveOrder)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD CancelOrder UNGUARDED
self~cancel
/*- - Help - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD about UNGUARDED
self~noMenuFunction(.HRSofv~HelpAbout)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD noMenuFunction UNGUARDED
use arg title
ret = MessageDialog(.HRSofv~NoMenu, self~hwnd, title, 'WARNING')
/*----------------------------------------------------------------------------
Methods to tidy up when Order Form is closed.
---------------------------------------------------------------------------*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Cancel: This method over-rides the default Windows action of 'cancel window'
for an Escape key. 'endExecution' (via the closeControlDialogs method
is required else dialog hangs when user tried to close.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD cancel
expose tabContent controlDialogsClosed
--say "OrderFormView-cancel-01."
if controlDialogsClosed = .true then do
--say "OrderFormView-cancel-02: Control Dialogs closed."
self~deRegisterInterest("appClosing",self) -- de-register interest in any events
return self~cancel~super
end
else do -- Control dialogs not yet cancelled
response = askDialog(.HRSofv~QExit, "N")
--say "OrderFormView-cancel-03: response =" response
if response = 1 then do -- '1' means the 'Yes' button pressed
self~deRegisterInterest("appClosing",self) -- de-register interest in any events
self~closeControlDialogs
return self~cancel:super
end
-- if response = 0 then do nothing - user chnaged his/her mind about closing.
end
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD ok
-- Invoked when enter key pressed - if passed to superclass, cancels dialog.
say "OrderFormView-ok-01."
return -- do not close dialog - appears as a no-op to the user.
/*----------------------------------------------------------------------------
notify - Invoked by the Event Manager when a registered event occurs.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD notify PUBLIC
expose controlDialogsClosed
use strict arg event
--say "OrderFormView-notify-01: event =" event
if event = "appClosing" then do
self~closeControlDialogs
controlDialogsClosed = .true
end
/*----------------------------------------------------------------------------
closeControlDialogs.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD closeControlDialogs PRIVATE
expose tabContent
do dlg over tabContent
dlg~endExecution(.false)
end
/*----------------------------------------------------------------------------
myFormat - A routine to format numbers into currency - e.g. converts
"123456" into "1.234.56".
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::ROUTINE myFormat
use arg number
number = number~right(9,0) -- left-pad with zeros
parse var number mill 2 thou 5 hun 8 dec
decs = "."||dec
select
when mill > 0 then number = mill||","||thou||","||hun||decs
when thou > 0 then number = thou~strip(,0)||","||hun||decs
when hun > 0 then number = hun~strip(,0)||decs
otherwise number = "0"||decs
end
return number
/*--------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
deRegisterInterest - tell Event Manager that any events registered are no
longer of interest.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/* ::METHOD deRegisterInterest PRIVATE
expose eventMgr
--say "OrderFormView-deRegisterInterest-01."
eventMgr~deRegisterInterest("appClosing",self)
*/
/*----------------------------------------------------------------------------
leaving - invoked by ooDialog when a dialog closes - but not when it's
closed by closing the app - i.e. closing OrderMgrView.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD leaving UNGUARDED
expose tabcontent cd1 cd2
--say "OrderFormView-leaving-01."
/* do dlg over tabContent
dlg~endExecution(.false)
end
*/ --forward class (super) continue
/*----------------------------------------------------------------------------
Methods to set up Control Dialogs
---------------------------------------------------------------------------*/
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
calculateDisplayArea
- - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD calculateDisplayArea PRIVATE
expose tabControl displayRect
-- Given a rectangle describing the tab control's size and position, the tab
-- control itself will calculate the display area's size and position.
r = tabControl~windowRect
tabControl~calcDisplayRect(r)
-- Save the size of the display area, we need it later.
s = .Size~new(r~right - r~left, r~bottom - r~top)
-- Now we need to map the display area's position on the screen, to the client
-- co-ordinates of the main dialog. The control dialog(s) are children windows
-- of the main dialog, which is why we need to use the client-area of the
-- dialog, not the client area of the tab control.
p = .Point~new(r~left, r~top)
self~screen2client(p)
-- Create our display rectangle. This is used in setWindowPosition(), which
-- takes a point / size rectangle. ooDialog defines a point / size rectangle
-- as using the left and top attributes for the position of the upper left
-- corner of a rectangle, using the right attribute for the width of the
-- rectangle, and using the bottom attribute for the height of the rectangle.
displayRect = .Rect~new(p~x, p~y, s~width, s~height)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
positionAndShow()
Used to resize and reposition one of the control dialogs so it occupies
the display area of the tab control.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD positionAndShow private
expose tabControl tabContent displayRect lastSelected havePositioned
use strict arg index
--say "OrderFormView-positionAndShow-01; index =" index
-- We can not position the control dialog until the underlying Windows dialog
-- is created. If the system is heavily loaded for some reason, this may not
-- have happened yet. We need to wait for it.
dlg = tabContent[index]
do i = 1 to 10
if dlg~hwnd <> 0 then leave
z = SysSleep(.01)
end
--say "OrderFormView-positionAndShow-02."
if dlg~hwnd == 0 then do
say "Error creating dialog for the tab with index:" index", aborting"
return self~cancel
end
if lastSelected <> 0 then tabContent[lastSelected]~hide
-- Now resize and reposition the control dialog to the tab control's display
-- area. We need to position the control dialog *above* the tab control in
-- the Z-order so that it shows.
dlg~setWindowPos(tabControl~hwnd, displayRect, "SHOWWINDOW NOOWNERZORDER")
--say "OrderFormView-positionAndShow-03."; say
lastSelected = index
havePositioned[index] = .true
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
onNewTab - Invoked when user selects another tab.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD onNewTab
expose tabControl tabContent havePositioned lastSelected
--say "OrderFormView-onNewTab-01."
index = tabControl~selectedIndex + 1
--say "OrderFormView-onNewTab-02: index =" index
dlg = tabContent[index]
--say "OrderFormView-onNewTab-03: dlg, havePositioned[index] =" dlg havePositioned[index]
if havePositioned[index] then do
last = tabContent[lastSelected]
last~hide
dlg~show
lastSelected = index
end
else do
--dlg~ownerDialog = self
--dlg~execute
self~positionAndShow(index)
end
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD prep
expose tabContent lastSelected havePositioned
use strict arg tabContent
--say "OrderFormView-prep-01."
-- The havePositioned array is used to determine if the page dialogs have been
-- positioned or not. Mark all 5 dialogs as not having been positioned yet.
havePositioned = .array~of(.false, .false)
-- No tab has been selected yet
lastSelected = 0
-- Connect the event handling methods to the events we are interested in.
--self~connectButtonEvent(IDC_PB_PREVIOUS, CLICKED, onPrevious)
--self~connectButtonEvent(IDC_PB_NEXT, CLICKED, onNext)
self~connectTabEvent(IDC_ORDFORM_TABS, SELCHANGE, onNewTab)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*============================================================================*/
/*==============================================================================
CustomerDetailsDlg - a Page in the OrderFormView
------------------
The "view" (or "gui") Customer Ordering part of the OrderFormView component.
----------------------------------------------------------------------------*/
::CLASS CustomerDetailsDlg SUBCLASS RcControlDialog
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
initDialog
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD initDialog
expose pbFindCust ecCustNum ecCustName ecCustAddr ecCustDisc objectMgr
--say "OrderFormView/CustomerDetailsDlg-initDialog-01: tabControl =" tabControl
-- Get ObjectMgr object id for later use.
objectMgr = .local~my.objectMgr
ecCustNum = self~newEdit("IDC_CUSTDTLS_NUM")
ecCustName = self~newEdit("IDC_CUSTDTLS_NAME")
ecCustAddr = self~newEdit("IDC_CUSTDTLS_ADDR")
ecCustDisc = self~newEdit("IDC_CUSTDTLS_DISC")
pbFindCust = self~newPushButton("IDC_CUSTDTLS_FIND")
-- pfFindCust is disabled in the .rc file, and is enabled when the focus
-- is placed on the Customer Number field. The button is disabled when pushed.
self~connectEditEvent("IDC_CUSTDTLS_NUM","GOTFOCUS",custNumGotFocus)
self~connectButtonEvent("IDC_CUSTDTLS_FIND","CLICKED",findCustomer)
--say "CustomerDetailsDlg-initDialog-01."
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setOrderFormDlg - Invoked by OrderFormView dialog so that this Control Dialog
can communicate with OrderFormView.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD setOrderFormDlg
expose dlgOrderForm
use arg dlgOrderForm
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
CustNumGotFocus - invoked when user puts focus on Customer Number field,
in which case the "Find Customer" pushbutton is enabled.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD CustNumGotFocus UNGUARDED
expose pbFindCust
--say "CustomerDetailsDlg-CustNumGotFocus-01."
pbFindCust~style = "DEFPUSHBUTTON"
pbFindCust~enable
--self~focusControl("IDC_CUSTDTLS_FIND")
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
findCustomer - invoke when the "Find Customer" button is pressed.
Gets Customer details for the Cust Number in ecCustNum.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD findCustomer UNGUARDED
expose ecCustNum ecCustName ecCustAddr ecCustDisc pbFindCust objectMgr dlgOrderForm
--say "CustomerDetailsDlg-findCust-01."
custNo = ecCustNum~getLine(1)
idCust = objectMgr~getComponentId("CustomerModel",custNo)
--say "OrderFormView/CustomerDetailsDlg-findCustomer-01: idCustNo =" idCust
if idCust = .false then do
r = ErrorDialog(.HRSofv~noCust)
pbFindCust~disable
return
end
dirCustData = idCust~query
if dirCustData = .false then do
say "OrderFormView/CustomerDetailsDlg-findCustomer-02: query returned error."
return
end
self~setCustomer(dirCustData)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
getCustomer - invoked by main OrderFormView dialog when a Customer is
dropped on the Order Form.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD getCustomer UNGUARDED
expose ecCustNum
use strict arg customerId
dirCustData = customerId~query
-- set Customer Number in dialog control - this not done by the setCustomer
-- method because it's keyed in by the user when not using drag/drop.
ecCustNum~setText(dirCustData["CustNo"])
self~setCustomer(dirCustData)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setCustomer - invoke when a Customer is dropped on the Order Form.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD setCustomer UNGUARDED
expose ecCustNum ecCustName ecCustAddr ecCustDisc pbFindCust objectMgr dlgOrderForm
use strict arg dirCustData
-- Got Cust details - now populate controls (Name, Address, Discount):
ecCustName~setText(dirCustData["CustName"])
-- Replace commas with eols:
strCustAddr = dirCustData["CustAddr"]~changeStr(",",.endOfLine)
-- Add the zip:
strCustAddr = strCustAddr||" "||dirCustData["Zip"]
ecCustAddr~setText(strCustAddr)
ecCustDisc~setText(dirCustData["CustDisc"])
-- disble the "Find Customer" button.
pbFindCust~disable
-- Finally, tell the OrderFormView about what the Customer discount code is:
dlgOrderForm~setCustDiscount(dirCustData["CustDisc"])
-- Re-calc totals to take account of Customer Discount if Cust entered after
-- order lines or a different Customer is selected half-way through the order.
dlgOrderForm~showTotals(0) -- provide ordeLineAmount as zero.
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*==============================================================================
OrderLinesDlg - a Page in the OrderFormView
-------------
The "view" (or "gui") Products Ordering part of the OrderFormView.
----------------------------------------------------------------------------*/
::CLASS OrderLinesDlg SUBCLASS RcControlDialog INHERIT View
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
initDialog
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD initDialog
expose objectMgr ecProdNum ecQty lvOrderItems
-- Get ObjectMgr object id for later use.
objectMgr = .local~my.objectMgr
lvOrderItems = self~newListView("IDC_ORDLINES_LIST")
lvOrderItems~addExtendedStyle(GRIDLINES FULLROWSELECT)
lvOrderItems~insertColumnPX(0,"ProdNo", 50,"LEFT")
lvOrderItems~insertColumnPX(1,"Product Name", 150,"LEFT")
lvOrderItems~insertColumnPX(2,"UOM", 40,"RIGHT")
lvOrderItems~insertColumnPX(3,"Qty", 40,"RIGHT")
lvOrderItems~insertColumnPX(4,"Amount", 60,"RIGHT")
--say "OrderLinesDlg-initDialog-01."
-- Test an edit field:
ecProdNum = self~newEdit("IDC_ORDLINES_PRODNO")
--say "OrderLinesDlg-initDialog-02; ecProdNum =" ecProdNum
ecQty = self~newEdit("IDC_ORDLINES_QTY")
pbAddOrderLine = self~newPushButton("IDC_ORDLINES_ADD")
self~connectEditEvent("IDC_ORDLINES_PRODNO","GOTFOCUS",prodNumGotFocus)
self~connectButtonEvent("IDC_ORDLINES_ADD","CLICKED",addOrderLine)
self~connectButtonEvent("IDC_ORDLINES_DELETE","CLICKED",deleteOrderLine)
self~connectListViewEvent("IDC_ORDLINES_LIST","ACTIVATE",showProduct) -- double-click
--say "OrderLinesDlg-initDialog-03: ecProdNum =" ecProdNum
-- Set focus on the Product Number field:
self~focusControl("IDC_ORDLINES_PRODNO")
--pbAddOrderLine~state = "FOCUS"
self~initView -- required by View mixin.
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setOrderFormDlg - Invoked by OrderFormView dialog so that this Control Dialog
can communicate with OrderFormView.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD setOrderFormDlg
expose OrderFormDlg
use arg OrderFormDlg
--say "OrderFormView/OrderLinesDlg-setOrderFormDlg-01."
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
prodNumGotFocus
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD prodNumGotFocus UNGUARDED
return
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
addOrderLine - invoked when user presses the "Add OrderLine" button.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD addOrderLine UNGUARDED
expose ecProdNum ecQty lvOrderItems objectMgr OrderFormDlg
--say "OrderFormView/OrderLinesDlg-addOrderLine-01."
-- Get data that user has entered:
prodNum = ecProdNum~getLine(1)
qtyOrdered = ecQty~getLine(1)
--say "OrderFormView/OrderLinesDlg-addOrderLine-02: prodNum =" prodNum
if qtyOrdered < 1 then do
r = ErrorDialog(.HRSofv~noQty)
return
end
-- Get product details from Product Model component:
idProduct = objectMgr~getComponentId("ProductModel",prodNum)
--say "OrderFormView/OrderLinesDlg-addOrderLine-03: idProduct =" idProduct
if idProduct = .false then do
r = ErrorDialog(.HRSofv~noProduct)
--pbFindCust~disable
return
end
dirProductData = idProduct~query
if dirProductData = .false then do
say "OrderFormView//OrderLinesDlg-addOrderLine-04: Product not found."
return
end
-- State at this point: Product found and qty entered.
-- Calculate Total Price:
total = qtyOrdered*dirProductData["ListPrice"]
--say "OrderFormView/OrderLinesDlg-addOrderLine-05: total =" total
-- Ensure display total has 2 decimal places:
--displayTotal = total/100~format(,2)
displayTotal = myFormat(total)
lvOrderItems~addRow( , , prodnum, dirProductData["ProdName"], -
dirProductData["UOM"], qtyOrdered, displayTotal)
-- Send amount of Order to the OrderFormView dialog:
OrderFormDlg~showTotals(total)
-- Blank out fields ready for next order line:
ecProdNum~settext("")
ecQty~settext("")
self~focusControl("IDC_ORDLINES_PRODNO")
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
getProduct - invoked by main OrderFormView dialog when a Product is
dropped on the Order Form.
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD getProduct UNGUARDED
expose ecProdNum
use strict arg productId
--say "OrderFormView/OrderLinesDlg-getProduct: ecProdNum =" ecProdNum
--trace i
dirProdData = productId~query
-- set Product Number in dialog control:
ecProdNum~setText(dirProdData["ProdNo"])
self~focusControl("IDC_ORDLINES_QTY")
--trace off
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
deleteOrderLine
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD deleteOrderLine
expose lvOrderItems
item = lvOrderItems~selected
say "OrderFormView/OrderLinesDlg-01: item selected =" item
if item = -1 then do -- if no item selected.
r = ErrorDialog(.HRSofv~noOrdLine)
return
end
lvOrderItems~delete(item)
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD rootDialog
expose rootDlg
use strict arg rootDlg
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
showProduct
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD showProduct UNGUARDED
expose lvOrderItems rootDlg
item = lvOrderItems~selected
if item = -1 then do
ret = MessageDialog(.HRSofv~nilSelected, self~hwnd, title, 'WARNING')
return
end
info = .Directory~new
if lvOrderItems~getItemInfo(item, info) then do
--say "OrderLinesDlg-showProduct-01: info~text =" info~text "rootDlg =" rootDlg
r = self~showModel:super("ProductModel", info~text, rootDlg)
end
else do
say "OrderLinesDlg-showProduct-04: ~getItemInfo returned .false."
end
/*----------------------------------------------------------------------------
leaving - invoked by ooDialog when a dialog closes.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD leaving UNGUARDED
--expose objectMgr viewClass viewInstance
--objectMgr~removeView(viewClass, viewInstance)
--say "OrderFormView/OrderLinesDlg-leaving-01."
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*============================================================================*/
/*//////////////////////////////////////////////////////////////////////////////
==============================================================================
OrderTotals v01-00 03May13
-----------
This class is the set of Order Totals.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::CLASS OrderTotals PUBLIC
::ATTRIBUTE amount
::ATTRIBUTE discount
::ATTRIBUTE discountedAmount
::ATTRIBUTE tax
::ATTRIBUTE taxedAmount
::METHOD init
self~amount = 0.00
self~discount = 0.00
self~discountedAmount = 0.00
self~tax = 0.00
self~taxedAmount = 0.00
/*//////////////////////////////////////////////////////////////////////////////
==============================================================================
PROBABLY REUNDANT!!
Order Grid (OrderGrid) v01-00 03May13
--------
This class is a table or grid of Order Line Items.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::CLASS OrderGrid PRIVATE
::ATTRIBUTE lines -- Array of Order lines
::ATTRIBUTE totals
::ATTRIBUTE numLines
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
init - set up Order Grid
- - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD init
self~lines = .array~new
self~totals = .array~new
self~totals[1,1]=0;
self~totals[2,1]=0; self~totals[2,2]=0
self~totals[3,1]=0; self~totals[3,2]=0
self~numLines = 0
::METHOD addLine
use strict arg dirLine
::METHOD delLine
use strict arg lineNo
/*- - - - - - - - - - - - - - - - - - - - - - - - - */
/*//////////////////////////////////////////////////////////////////////////////
==============================================================================
Order Header v01-00 06May13
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::CLASS OrderHeader
::attribute orderNumber
::attribute orderDate
::attribute custNo
::attribute custName
::attribute address
::attribute discount
/*============================================================================*/
/*//////////////////////////////////////////////////////////////////////////////
==============================================================================
Order Line v01-00 06May13
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::CLASS OrderLine
::attribute prodNo
::attribute prodName
::attribute UOM
::attribute qty
::attribute amount
/*============================================================================*/
/*//////////////////////////////////////////////////////////////////////////////
==============================================================================
Human-Readable Strings (HRSofv) v01-00 07Jun12
--------
The HRSofv class provides constant character strings for user-visible messages.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::CLASS HRSofv PRIVATE -- Human-Readable Strings
::CONSTANT CancelOrder "Cancel Order"
::CONSTANT HelpAbout "Help - About"
::CONSTANT nilSelected "Please select an item first."
::CONSTANT NoBtn "This button is not yet implemented."
::CONSTANT NoCust "Customer not found."
::CONSTANT NoOrdLine "No Order Line selected."
::CONSTANT NoMenu "This menu item is not yet implemented."
::CONSTANT NoProduct "Product not found."
::CONSTANT NoQty "No valid quantity."
::CONSTANT PlaceOrder "Place Order"
::CONSTANT QExit "Are you sure you want to cancel this Order and throw away all changes?"
::CONSTANT SaveOrder "Save Order"
/*============================================================================*/