Files
MBS/TEST/MultipleDialogs/MultiMasterDetail/CustOrders.4gl
T

491 lines
15 KiB
Plaintext

# Property of Four Js*
# (c) Copyright Four Js 1995, 2019. All Rights Reserved.
# * Trademark of Four Js Development Tools Europe Ltd
# in the United States and elsewhere
#
# Four Js and its suppliers do not warrant or guarantee that these
# samples are accurate and suitable for your purposes. Their inclusion is
# purely for information purposes only.
IMPORT FGL CityList
IMPORT FGL OrderInput
IMPORT FGL MsgBox
GLOBALS "Globals.4gl"
DEFINE cust_curr INTEGER
DEFINE cust, old_cust custrec
DEFINE cust_state SMALLINT
CONSTANT STATE_NAVIGATE = 0
CONSTANT STATE_MODIFY = 1
CONSTANT STATE_APPEND = 2
CONSTANT otitle = "Customer"
MAIN
DEFINE ordlist_lastrow INTEGER
OPTIONS INPUT WRAP
OPEN FORM f_cust FROM "CustOrders"
DISPLAY FORM f_cust
DIALOG ATTRIBUTES(FIELD ORDER FORM, UNBUFFERED)
INPUT cust.* FROM custrec.* ATTRIBUTES(WITHOUT DEFAULTS)
ON CHANGE custrec.cust_name
IF NOT cust_check_name(DIALOG) THEN NEXT FIELD CURRENT END IF
ON CHANGE custrec.cust_address
IF NOT cust_check_address(DIALOG) THEN NEXT FIELD CURRENT END IF
ON CHANGE custrec.cust_state
INITIALIZE cust.cust_city, cust.cust_zipcode, cust.cust_address TO NULL
END INPUT
DISPLAY ARRAY orders TO ordlist.*
BEFORE ROW
MESSAGE SFMT("Order record %1 / %2", DIALOG.getCurrentRow("ordlist"), DIALOG.getArrayLength("ordlist"))
AFTER ROW
LET ordlist_lastrow = arr_curr()
END DISPLAY
BEFORE DIALOG
CALL cust_loadlist(DIALOG,100)
CALL cust_move_to(DIALOG, 1)
ON ACTION zoom_city
CALL cust_zoom_city(DIALOG)
ON ACTION cust_query
CALL cust_query(DIALOG)
ON ACTION cust_first
CALL cust_move_to(DIALOG, 1)
ON ACTION cust_previous
CALL cust_move_to(DIALOG, cust_curr - 1)
ON ACTION cust_next
CALL cust_move_to(DIALOG, cust_curr + 1)
ON ACTION cust_last
CALL cust_move_to(DIALOG, customers.getLength())
ON ACTION dialogtouched
CALL cust_touched(DIALOG)
ON ACTION cust_append
IF NOT cust_append(DIALOG) THEN CONTINUE DIALOG END IF
NEXT FIELD cust_name
ON ACTION cust_delete -- VALIDATE=NO
CALL cust_delete(DIALOG)
DISPLAY BY NAME cust.*
ON ACTION cust_undo -- VALIDATE=NO
CALL cust_undo(DIALOG)
DISPLAY BY NAME cust.*
ON ACTION cust_save
IF NOT cust_save(DIALOG) THEN CONTINUE DIALOG END IF
ON ACTION ord_append
CALL ord_append(DIALOG)
ON ACTION ord_modify
CALL ord_modify(DIALOG)
ON ACTION ord_delete
CALL ord_delete(DIALOG)
ON ACTION close
IF cust_check_changed(DIALOG) THEN EXIT DIALOG END IF
END DIALOG
END MAIN
FUNCTION cust_zoom_city(d)
DEFINE d ui.Dialog
DEFINE s INTEGER
DEFINE name, state STRING
CALL select_city(d.getFieldBuffer("cust_city")) RETURNING s, name, state
IF s==0 THEN
LET cust.cust_city = name
LET cust.cust_state = state
CALL d.setFieldTouched("cust_city",TRUE)
CALL d.setFieldTouched("cust_state",TRUE)
CALL cust_touched(d)
END IF
END FUNCTION
FUNCTION cust_touched(d)
DEFINE d ui.Dialog
LET cust_state = STATE_MODIFY
CALL cust_setup(d)
END FUNCTION
FUNCTION cust_check_changed(d)
DEFINE d ui.Dialog
DEFINE r INTEGER
IF cust_modifying() THEN
CALL cust_setup(d)
LET r = mbox_ync(otitle,"Do you want to save your changes?","question")
IF r == 1 THEN
IF NOT cust_save(d) THEN LET r = 3 END IF
END IF
IF r == 2 THEN
CALL cust_clean(d)
END IF
RETURN (r == 1 OR r == 2)
END IF
RETURN TRUE
END FUNCTION
FUNCTION cust_modifying()
RETURN cust_state != STATE_NAVIGATE
END FUNCTION
FUNCTION cust_undo(d)
DEFINE d ui.Dialog
CASE cust_state
WHEN STATE_MODIFY
IF NOT mbox_yn(otitle,"Undo customer modification?","question") THEN RETURN END IF
LET cust.* = old_cust.*
CALL cust_clean(d)
WHEN STATE_APPEND
IF NOT mbox_yn(otitle,"Cancel customer creation?","question") THEN RETURN END IF
CALL customers.deleteElement(customers.getLength())
CALL cust_clean(d)
CALL cust_move_to(d, customers.getLength())
END CASE
END FUNCTION
FUNCTION cust_verify_address_format(value)
DEFINE value STRING
DEFINE num STRING, p,x INTEGER
IF value IS NULL THEN RETURN TRUE END IF
LET p = value.getIndexOf(",", 1)
IF p == 0 THEN RETURN FALSE END IF
LET num = value.subString(1, p)
LET x = num
IF x <= 0 THEN RETURN FALSE END IF
IF value.getLength() <= p THEN RETURN FALSE END IF
RETURN TRUE
END FUNCTION
FUNCTION cust_check_name(d)
DEFINE d ui.Dialog
IF LENGTH(cust.cust_name) = 0 THEN
CALL mbox_ok(otitle,"You must specify a customer name.","stop")
RETURN FALSE
END IF
IF cust.cust_name MATCHES "*[@#$%^&]*" THEN
CALL mbox_ok(otitle,"The customer name containts invalid characters.","stop")
RETURN FALSE
END IF
RETURN TRUE
END FUNCTION
FUNCTION cust_check_address(d)
DEFINE d ui.Dialog
IF NOT cust_verify_address_format(cust.cust_address) THEN
CALL mbox_ok(otitle,"Address must hold a number followed by a comma and the street name.","stop")
RETURN FALSE
END IF
RETURN TRUE
END FUNCTION
FUNCTION cust_check_city(d)
DEFINE d ui.Dialog
-- Inter-dependent field validation
IF cust.cust_city IS NULL AND cust.cust_zipcode IS NOT NULL THEN
CALL mbox_ok(otitle,"You must specify a city because zipcode is not null.","stop")
RETURN FALSE
END IF
RETURN TRUE
END FUNCTION
FUNCTION cust_check_data(d)
DEFINE d ui.Dialog
IF d.validate("custrec.*") < 0 THEN
RETURN "*"
END IF
IF NOT cust_check_name(d) THEN RETURN "custrec.cust_name" END IF
IF NOT cust_check_city(d) THEN RETURN "custrec.cust_city" END IF
IF NOT cust_check_address(d) THEN RETURN "custrec.cust_address" END IF
RETURN NULL -- data is valid
END FUNCTION
FUNCTION cust_check_fields(d)
DEFINE d ui.Dialog
DEFINE fn STRING
LET fn = cust_check_data(d)
IF fn IS NULL THEN RETURN TRUE END IF
IF fn != "*" THEN CALL d.nextField(fn) END IF
RETURN FALSE
END FUNCTION
FUNCTION cust_save(d)
DEFINE d ui.Dialog
IF NOT cust_check_fields(d) THEN RETURN FALSE END IF
IF cust_state == STATE_APPEND THEN
-- SQL INSERT ...
END IF
IF cust_state == STATE_MODIFY THEN
-- SQL UPDATE ...
END IF
LET customers[cust_curr].* = cust.*
CALL cust_clean(d)
CALL mbox_ok("Customers", "Changes saved to database", "information")
CALL d.setFieldTouched("custrec.*",FALSE)
CALL cust_setup(d)
RETURN TRUE
END FUNCTION
FUNCTION cust_append(d)
DEFINE d ui.Dialog
IF NOT cust_autosave(d) THEN RETURN FALSE END IF
INITIALIZE cust.* TO NULL
CALL ord_loadlist(d,0,0)
LET cust.cust_id = cust_curr + 101044
LET cust_state = STATE_APPEND
CALL customers.appendElement()
LET cust_curr = customers.getLength()
CALL cust_setup(d)
RETURN TRUE
END FUNCTION
FUNCTION cust_delete(d)
DEFINE d ui.Dialog
IF cust_curr<= 0 THEN RETURN END IF
IF cust_modifying() THEN
CALL cust_setup(d)
IF NOT mbox_yn(otitle,"Cancel current changes?","question") THEN RETURN END IF
CALL cust_clean(d)
ELSE
IF NOT mbox_yn(otitle,"Delete current customer?","question") THEN RETURN END IF
END IF
-- SQL DELETE ...
CALL customers.deleteElement(cust_curr)
IF customers.getLength()==0 THEN
CALL mbox_ok(otitle,"No more customers in list, switching to query mode","stop")
CALL cust_query(d)
RETURN
END IF
IF cust_curr>customers.getLength() THEN
LET cust_curr=customers.getLength()
END IF
CALL cust_move_to(d,cust_curr)
CALL cust_setup(d)
END FUNCTION
FUNCTION cust_query(d)
DEFINE d ui.Dialog
DEFINE sql STRING
IF NOT cust_check_changed(d) THEN RETURN END IF
DISPLAY "Enter customer search criterias" TO cust_info
WHILE TRUE
LET int_flag = FALSE
CONSTRUCT BY NAME sql ON cust_id, cust_name, cust_state,
cust_city, cust_zipcode, cust_address, cust_checked
ATTRIBUTES( CANCEL=FALSE, ACCEPT=FALSE )
ON ACTION close
IF mbox_yn(otitle,"Quit application?","question") THEN EXIT PROGRAM END IF
ON ACTION cust_fetch
ACCEPT CONSTRUCT
END CONSTRUCT
IF NOT int_flag THEN
-- Dummy query, should use database query instead.
CALL cust_loadlist(d,LENGTH(sql))
CALL cust_setup(d)
CALL mbox_ok(otitle,SFMT("Found %1 customer records in database",customers.getLength()),"information")
EXIT WHILE
END IF
END WHILE
END FUNCTION
FUNCTION cust_setup(d)
DEFINE d ui.Dialog
DEFINE has_rows, on_first, on_last, cust_ro INTEGER
LET has_rows = (cust_curr > 0 AND customers.getLength()>0)
LET on_first = (cust_curr == 1)
LET on_last = (cust_curr == customers.getLength())
LET cust_ro = (has_rows AND cust_state == STATE_NAVIGATE)
CALL d.setActionActive("dialogtouched", cust_ro)
CALL d.setActionActive("cust_undo", NOT cust_ro)
CALL d.setActionActive("cust_save", NOT cust_ro)
CALL d.setActionActive("cust_append", TRUE) -- always active
CALL d.setActionActive("cust_delete", has_rows) -- can delete creation
CALL d.setActionActive("cust_query", TRUE) -- always active
CALL d.setActionActive("cust_first", NOT on_first)
CALL d.setActionActive("cust_previous", NOT on_first)
CALL d.setActionActive("cust_next", NOT on_last)
CALL d.setActionActive("cust_last", NOT on_last)
CALL d.setActionActive("ord_append", cust_ro)
CALL d.setActionActive("ord_modify", cust_ro)
CALL d.setActionActive("ord_delete", cust_ro)
CASE cust_state
WHEN STATE_APPEND
DISPLAY "Creating a new customer record (save with ctrl-s)" TO cust_info
WHEN STATE_MODIFY
DISPLAY "Modifying current customer record (save with ctrl-s)" TO cust_info
OTHERWISE
DISPLAY SFMT("Customer record %1 / %2",cust_curr,customers.getLength()) TO cust_info
END CASE
END FUNCTION
FUNCTION cust_clean(d)
DEFINE d ui.Dialog
LET old_cust.* = cust.*
LET cust_state = STATE_NAVIGATE
CALL cust_setup(d)
END FUNCTION
FUNCTION cust_autosave(d)
DEFINE d ui.Dialog
IF cust_modifying() THEN
IF NOT cust_save(d) THEN RETURN FALSE END IF
END IF
RETURN TRUE
END FUNCTION
FUNCTION cust_move_to(d,index)
DEFINE d ui.Dialog
DEFINE index INTEGER
IF NOT cust_autosave(d) THEN RETURN END IF
IF index > customers.getLength() THEN
LET index = customers.getLength()
END IF
IF index < 1 THEN
LET index = 1
END IF
LET cust.* = customers[index].*
LET old_cust.* = cust.*
LET cust_curr = index
MESSAGE SFMT("Customer: %1/%2", cust_curr, customers.getLength())
CALL ord_loadlist(d, customers[index].cust_id, (index mod 5) * 3)
CALL d.setCurrentRow("ordlist",1)
CALL cust_setup(d)
END FUNCTION
-- Dummy function to fill the list of customers (normally, SELECT from database)
FUNCTION cust_loadlist(d,m)
DEFINE d ui.Dialog
DEFINE m,i INTEGER
CALL customers.clear()
FOR i=1 TO m
LET customers[i].cust_id = i
LET customers[i].cust_name = "Name " || i
LET customers[i].cust_state = "CA"
LET customers[i].cust_city = "San Fransisco"
LET customers[i].cust_zipcode = 94102
LET customers[i].cust_address = "52, Marlon Street"
LET customers[i].cust_checked = i mod 2
END FOR
IF customers.getLength()>0 THEN
LET cust_curr = 1
LET cust.* = customers[cust_curr].*
CALL ord_loadlist(d, customers[cust_curr].cust_id, (cust_curr mod 5) * 3)
ELSE
LET cust_curr = 0
INITIALIZE cust.* TO NULL
CALL ord_loadlist(d, 0, 0)
END IF
CALL cust_clean(d)
END FUNCTION
FUNCTION ord_loadlist(d,mid,m)
DEFINE d ui.Dialog
DEFINE mid,m,i INTEGER
CALL orders.clear()
FOR i=1 TO m
CALL orders.appendElement()
LET orders[i].ord_id = mid * 100 + i
LET orders[i].ord_crea = CURRENT YEAR TO SECOND
LET orders[i].ord_amount = ( i mod 5 ) * 133.56
END FOR
END FUNCTION
FUNCTION ord_append(d)
DEFINE d ui.Dialog
IF NOT cust_check_changed(d) THEN RETURN END IF
CALL ord_input('A', cust.cust_id, cust.cust_name, 0)
END FUNCTION
FUNCTION ord_modify(d)
DEFINE d ui.Dialog
IF NOT cust_check_changed(d) THEN RETURN END IF
IF d.getCurrentRow("ordlist")==0 THEN RETURN END IF
CALL ord_input('M', cust.cust_id, cust.cust_name, orders[d.getCurrentRow("ordlist")].ord_id)
END FUNCTION
FUNCTION ord_delete(d)
DEFINE d ui.Dialog
IF NOT cust_check_changed(d) THEN RETURN END IF
IF NOT mbox_yn(otitle,"Delete select order from database?","question") THEN
RETURN
END IF
CALL d.deleteRow("ordlist",d.getCurrentRow("ordlist"))
END FUNCTION
FUNCTION combo_fill_states(cb)
DEFINE cb ui.ComboBox
CALL cb.addItem("AK","Alaska")
CALL cb.addItem("AL","Alabama")
CALL cb.addItem("AR","Arkansas")
CALL cb.addItem("AZ","Arizona")
CALL cb.addItem("CA","California")
CALL cb.addItem("CO","Colorado")
CALL cb.addItem("CT","Connecticut")
CALL cb.addItem("DC","D.C.")
CALL cb.addItem("DE","Delaware")
CALL cb.addItem("FL","Florida")
CALL cb.addItem("GA","Georgia")
CALL cb.addItem("HI","Hawaii")
CALL cb.addItem("IA","Iowa")
CALL cb.addItem("ID","Idaho")
CALL cb.addItem("IL","Illinois")
CALL cb.addItem("IN","Indiana")
CALL cb.addItem("KS","Kansas")
CALL cb.addItem("KY","Kentucky")
CALL cb.addItem("LA","Louisiana")
CALL cb.addItem("MA","Massachusetts")
CALL cb.addItem("MD","Maryland")
CALL cb.addItem("ME","Maine")
CALL cb.addItem("MI","Michigan")
CALL cb.addItem("MN","Minnesota")
CALL cb.addItem("MO","Missouri")
CALL cb.addItem("MS","Mississippi")
CALL cb.addItem("MT","Montana")
CALL cb.addItem("NC","North Carolina")
CALL cb.addItem("ND","North Dakota")
CALL cb.addItem("NE","Nebraska")
CALL cb.addItem("NH","New Hampshire")
CALL cb.addItem("NJ","New Jersey")
CALL cb.addItem("NM","New Mexico")
CALL cb.addItem("NV","Nevada")
CALL cb.addItem("NY","New York")
CALL cb.addItem("OH","Ohio")
CALL cb.addItem("OK","Oklahoma")
CALL cb.addItem("OR","Oregon")
CALL cb.addItem("PA","Pennsylvania")
CALL cb.addItem("PR","Puerto Rico")
CALL cb.addItem("RI","Rhode Island")
CALL cb.addItem("SC","South Carolina")
CALL cb.addItem("SD","South Dakota")
CALL cb.addItem("TN","Tennessee")
CALL cb.addItem("TX","Texas")
CALL cb.addItem("UT","Utah")
CALL cb.addItem("VA","Virginia")
CALL cb.addItem("VT","Vermont")
CALL cb.addItem("WA","Washington")
CALL cb.addItem("WI","Wisconsin")
CALL cb.addItem("WV","West Virginia")
CALL cb.addItem("WY","Wyoming")
END FUNCTION