SourceForge has been redesigned. Learn more.
Close

[r8761]: / ooDialog / trunk / examples / userGuide / exercises / Exercise07 / Product / ProductView.rex  Maximize  Restore  History

Download this file

510 lines (424 with data), 23.6 kB

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
/*----------------------------------------------------------------------------*/
/* */
/* Copyright (c) 2011-2013 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: */
/* http://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 06: ProductView.rex - The ProductView component v01-01 06Jum12
Contains: classes "ProductView", "AboutDialog", and "HRSpv".
Pre-requisites: ProductView.dll, ProductView.h, Pproduct.ico, ProductIcon.bmp,
Support\NumberOnlyEditEx.cls (copied from ooDialog Samples
into the folder Exercise06\Support)
Description: A sample Product View component - part of the sample
Order Management application.
Outstanding Problems: None reported.
Changes:
v01-00 03Jun12: First version for Exercise05.
v01-01 06Jun12: Minor changes for Exercise06.
------------------------------------------------------------------------------*/
.Application~addToConstDir("Product\ProductView.h")
::requires "ooDialog.cls"
::requires "..\Support\NumberOnlyEditEx.cls"
::requires "Product\ProductModelsData.rex"
::REQUIRES "..\support\ResView.rex"
/*//////////////////////////////////////////////////////////////////////////////
==============================================================================
ProductView v01-01 06Jun12
-----------
The "view" part of the Product component. Now designed to operate from its own
folder. Should be invoked from immediately outside the Product folder.
[interface (idl format)]
Changes:
v01-00 03Jun12: First version.
v01-01 06Jun12: Minor changes for Exercise06.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::CLASS ProductView SUBCLASS ResView PUBLIC
::ATTRIBUTE dialogState PRIVATE -- States are: 'closable' or 'inUpdate".
/*----------------------------------------------------------------------------
Class Methods
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD newInstance CLASS PUBLIC UNGUARDED
use arg idModel, rootDlg --Ex07
if parent = "SA" then hasParent = .false; else hasParent = .true
say ".ProductView-newInstance-01: model, rootDlg =" idModel rootDlg
.Application~addToConstDir("Product\ProductView.h")
-- Create an instance of ProductView and show it:
--dlg = .ProductView~new("Product\res\ProductView.dll", IDD_PRODUCT_VIEW)
dlg = self~new("Product\res\ProductView.dll", IDD_PRODUCT_VIEW)
-- Check super (temp debug):
-- x = self~fred:super(); say "x =" x
say ".ProductView-newInstance-02: dlg =" dlg
dlg~activate(idModel, rootDlg) --Ex07
return dlg --Ex07
/*----------------------------------------------------------------------------
Instance Methods
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*----------------------------------------------------------------------------
Dialog Setup Methods
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD init
--say "ProductView-init-01."
forward class (super) continue
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD activate UNGUARDED
expose prodData
use arg idModel, rootDlg, prodData --Ex07- note: prodData is a ProductDT.
say "ProductView-activate-01. idModel, rootDlg =" idModel rootDlg
forward class (super) continue -- MVF: required to get Model's data
dirdata = RESULT -- MVF: model's data returned by super
prodData = dirData[DT]
say "ProductView-activate-02: rootDlg, prodData =" rootDlg prodData
self~dialogState = "closable"
if rootDlg = "SA" then self~execute("SHOWTOP","IDI_PROD_DLGICON") --ADDED FOR EXERCISE06.
else self~popUpAsChild(rootDlg,"SHOWTOP",,"IDI_PROD_DLGICON") --ADDED FOR EXERCISE06.
return
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD initDialog
expose menuBar prodControls prodData --Ex07
--say "ProductView-initDialog-01"
menuBar = .BinaryMenuBar~new(self, IDR_PRODUCT_VIEW_MENU, , self, .true)
prodControls = .Directory~new
prodControls[ecProdNo] = self~newEdit("IDC_PROD_NO")
prodControls[ecProdName] = self~newEdit("IDC_PROD_NAME")
prodControls[ecProdPrice] = self~newEdit("IDC_PROD_LIST_PRICE")
prodControls[ecUOM] = self~newEdit("IDC_PROD_UOM")
prodControls[ecProdDescr] = self~newEdit("IDC_PROD_DESCRIPTION")
prodControls[gbSizes] = self~newEdit("IDC_PROD_SIZE_GROUP")
prodControls[rbSmall] = self~newRadioButton("IDC_PROD_RADIO_SMALL")
prodControls[rbMedium] = self~newRadioButton("IDC_PROD_RADIO_MEDIUM")
prodControls[rbLarge] = self~newRadioButton("IDC_PROD_RADIO_LARGE")
prodControls[pbSaveChanges] = self~newPushButton("IDC_PROD_SAVE_CHANGES")
self~connectButtonEvent("IDC_PROD_SAVE_CHANGES","CLICKED",saveChanges)
-- Use NumberOnlyEditEx.cls to enforce numeric only entry for Price and UOM:
prodControls[ecProdPrice]~initDecimalOnly(2,.false) -- 2 decimal places, no sign.
prodControls[ecUOM]~initDecimalOnly(0,.false) -- 0 decimal places, no sign.
prodControls[ecProdPrice]~connectCharEvent(onChar)
prodControls[ecUOM]~connectCharEvent(onChar)
--prodData = self~getData -- Gets data from ProductModel into prodData
self~showData -- Show the data
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*----------------------------------------------------------------------------
Event Handler Methods - MenuBar Events:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD updateProduct UNGUARDED
expose prodControls
-- Enable the controls to allow changes to the data:
prodControls[ecProdName]~setReadOnly(.false)
prodControls[ecProdPrice]~setReadOnly(.false)
prodControls[ecUOM]~setReadOnly(.false)
prodControls[ecProdDescr]~setReadOnly(.false)
prodControls[rbSmall]~enable
prodControls[rbMedium]~enable
prodControls[rbLarge]~enable
self~enableControl("IDC_PROD_SAVE_CHANGES")
prodControls[pbSaveChanges]~state = "FOCUS" -- Put input focus on the button
self~tabToNext() -- put text cursor on Product Description
-- (as if the user had pressed tab)
self~dialogState = "inUpdate"
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD refreshData UNGUARDED
self~disableControl("IDC_PROD_SAVE_CHANGES")
self~showData
self~dialogState = "closable"
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD print UNGUARDED
-- say "ProductView-print-01"
ans = MessageDialog(.HRSpv~printMsg)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD close UNGUARDED
--say "ProductView-close-01"
return self~cancel:super
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD about UNGUARDED
--say "ProductView-about-01"
dlg = .AboutDialog~new("ProductView.dll", IDD_PRODUCT_VIEW_ABOUT)
dlg~execute("SHOWTOP")
/*----------------------------------------------------------------------------
Event Handler Methods - PushButton Events
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"Save Changes" - Collects new data, checks if there has indeed been a
change, and if not, issues a warning msg. Disables the
button when valid changes made. */
::METHOD saveChanges UNGUARDED
expose prodControls prodData
-- Transform data from view format (as in controls) to app format (a directory):
newProdData = self~xformView2App(prodControls)
-- Check if anything's changed; if not, show msgbox and exit with controls enabled.
-- If changed, go on to validate data.
result = self~checkForChanges(newProdData)
if result = .false then do
msg = .HRSpv~nilSaved
hwnd = self~dlgHandle
answer = MessageDialog(msg,hwnd,.HRSpv~updateProd,"OK","WARNING","DEFBUTTON2 APPLMODAL")
return
end
-- Now validate data:
result = self~validate(newProdData) -- returns a null string or error messages.
-- Better would be a set of error numbers.
-- If no problems, then show msgbox and go on to disable controls.
if result = "" then do
msg = .HRSpv~saved
hwnd = self~dlgHandle
answer = MessageDialog(msg,hwnd,.HRSpv~updateProd,"OK","INFORMATION","DEFBUTTON1 APPLMODAL")
end
-- If problems, then show msgbox and leave user to try again or refresh or exit.
else do
msg = result||.EndOfLine||.HRSpv~notSaved
hwnd = self~dlgHandle
answer = MessageDialog(msg,hwnd,.HRSpv~updateProd,"OK","ERROR","DEFBUTTON1 APPLMODAL")
return
end
-- Send new data to be checked by CustomerModel object (not implemented).
-- Disable controls that were enabled by menu "ActionsFile-->Update" selection:
prodControls[ecProdName]~setReadOnly(.true)
prodControls[ecProdDescr]~setReadOnly(.true)
prodControls[ecProdPrice]~setReadOnly(.true)
prodControls[ecUom]~setReadOnly(.true)
if newProdData~size \= "S" then prodControls[rbSmall]~disable
if newProdData~size \= "M" then prodControls[rbMedium]~disable
if newProdData~size \= "L" then prodControls[rbLarge]~disable
self~disableControl("IDC_PROD_SAVE_CHANGES")
self~dialogState = "closable"
prodData = newProdData
prodData~list
return
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*----------------------------------------------------------------------------
Event Handler Methods - Keyboard Events
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD onChar UNGUARDED
-- called for each character entered in the price or UOM fields.
forward to (arg(6))
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
"OK" - This is a no-op method that over-rides the default Windows action
of 'close window' for an Enter key --*/
::METHOD ok unguarded
return
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD cancel
-- If in the process of updating, then ask whether any changes should be
-- thrown away and dialog closed. If yes then close by calling the superclass,
-- else nop. If not in update, then close immediately
if self~dialogState = "inUpdate" then do
ans = MessageDialog(.HRSpv~closeInUpdate, self~dlgHandle, .HRSpv~updateIP, "YESNO", "WARNING", "DEFBUTTON2")
if ans = .PlainBaseDialog~IDYES then return self~cancel:super
else nop
end
else return self~cancel:super
/*----------------------------------------------------------------------------
Application Methods
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
--::METHOD getData -- Ex07 makes this method redundant
-- Get data from the ProductModel:
--expose prodData
--say "ProductView-getData-01."
-- idProductModel = .local~my.idProductModel
-- prodData = idProductModel~query -- prodData is of type ProductDT
-- return prodData
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD showData
-- Transfrom data (where necessary) to display format, and then disable controls.
expose prodControls prodData
say "ProductView-showData-01: prodData =" prodData
-- Set data in controls:
prodControls[ecProdNo]~setText( prodData~number )
prodControls[ecProdName]~setText( prodData~name )
-- Price in prodData has no decimal point - 2 decimal places are implied - hence /100 for display.
-- Pad with zeros if necessary.
displayPrice = (prodData~price/100)~format(,2) -- corrected in Ex07
prodControls[ecProdPrice]~setText(displayPrice)
prodControls[ecUOM]~settext( proddata~uom )
prodControls[ecProdDescr]~setText(prodData~description )
size = prodData~size
-- Disable controls
prodControls[ecProdName]~setReadOnly(.true)
prodControls[ecProdPrice]~setReadOnly(.true)
prodControls[ecUOM]~setReadOnly(.true)
prodControls[ecProdDescr]~setReadOnly(.true)
prodControls[rbSmall]~disable
prodControls[rbMedium]~disable
prodControls[rbLarge]~disable
-- But check correct button and enable it to highlight it to the user:
select
when size = "S" then do
.RadioButton~checkInGroup(self,"IDC_PROD_RADIO_SMALL","IDC_PROD_RADIO_LARGE","IDC_PROD_RADIO_SMALL")
prodcontrols[rbSmall]~enable
end
when size = "M" then do
.RadioButton~checkInGroup(self,"IDC_PROD_RADIO_SMALL","IDC_PROD_RADIO_LARGE","IDC_PROD_RADIO_MEDIUM")
prodcontrols[rbMedium]~enable
end
otherwise do
.RadioButton~checkInGroup(self,"IDC_PROD_RADIO_SMALL","IDC_PROD_RADIO_LARGE","IDC_PROD_RADIO_LARGE")
prodcontrols[rbLarge]~enable
end
end
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD checkForChanges
-- Check whether any data has actually changed when "Save Changes" button
-- has been pressed. Return .true if data changed, else returns .false.
expose prodData
use arg newProdData
changed = .false
select
when newProdData~name \= prodData~name then changed = .true
when newProdData~price \= prodData~price then changed = .true
when newProdData~uom \= prodData~uom then changed = .true
when newProdData~description \= prodData~description then changed = .true
when newProdData~size \= ProdData~size then changed = .true
otherwise nop
end
return changed
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD validate
-- Validation: 1. Check price/UOM not changed > 50% up or down.
-- 2. Cannot change from Large to Small without UOM increasing
-- by at least 100%; nor from Small to Large without
-- decreasing by more than 50%.
-- 3. Product Description <= 100 characters.
-- 4. Product Name <= 30 characters.
-- Returns string of messages - the null string if all OK.
expose prodData
use arg newProdData
msg = ""
-- Check Price (catches decimal point errors also):
price = prodData~price; newPrice = newProdData~price
oldUom = prodData~uom; newUom = newProdData~uom -- 'oldUom - avoids name conflict with 'uom' in newProddata~uom.
if ((price/oldUom)*1.5 < newPrice/newUom) | (newPrice/newUom < (price/oldUom)/2) then do
msg = msg||.HRSpv~badRatio||" "
end
-- Check Size vs UOM:
if prodData~size = "L" & newProdData~size = "S" - -- Large to Small
& prodData~uom/2 < newProdData~uom then do
msg = msg||.HRSpv~uomTooBig||" "
end
if prodData~size = "S" & newProdData~size = "L" - -- Small to Large
& prodData~uom*2 > newProdData~uom then do
msg = msg||.HRSpv~uomTooSmall||" "
end
-- Check Product Description length:
if newProdData.description~length > 80 then do
msg = msg||.HRSpv~descrTooBig||" "
end
-- Check Product Name length:
if newProdData~name~length > 30 then do
msg = msg||.HRSpv~prodNameTooBig
end
return msg
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::METHOD xformView2App
-- Transforms Product Data from View form (in the GUI controls) to
-- App form (a directory with address as an array).
expose prodControls
prodData = .ProductDT~new
prodData~number = prodControls[ecProdNo]~gettext()
prodData~name = prodControls[ecProdName]~getText()
price = prodControls[ecProdPrice]~getText()
-- Data entered has or assumes a decimal point; but data in "application"
-- is a whole number (e.g. $42.42 is recorded in the database as "4242").
-- So re-format data from decimal to whole number:
priceTwoDecs = price~format(,2) -- force 2 dec positions
-- Re-display price properly formatted (in case the user did not format correctly - e.g. entered "42" or "38.4"):
prodControls[ecProdPrice]~setText(priceTwoDecs)
-- Now format price to "application" format:
price = (priceTwoDecs*100)~format(,0) -- multiply by 100 and then force whole number.
prodData~price = price
prodData~uom = prodControls[ecUOM]~getText()
prodData~description = prodControls[ecProdDescr]~getText()
select
when prodControls[rbSmall]~checked then prodData~size = "S"
when prodControls[rbMedium]~checked then prodData~size = "M"
otherwise prodData~size = "L"
end
return prodData
/*============================================================================*/
/*//////////////////////////////////////////////////////////////////////////////
==============================================================================
AboutDialog v01-00 03Jun12
-------------
The "About" class - shows a dialog box that includes a bitmap - part of the
ProductView component.
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::CLASS AboutDialog SUBCLASS ResDialog
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::method initDialog
expose font image
resImage = .ResourceImage~new( "", self) -- Create an instance of a resource image
image = resImage~getImage(IDB_PROD_ICON) -- Create an image from the Product bitmap
stImage = self~newStatic(IDC_PRODABT_ICON_PLACE)~setImage(image) -- Create a static text control and set the image in it
font = self~createFontEx("Ariel", 12) -- Create up a largish font with which to display text and ...
self~newStatic(IDC_PRODABT_STATIC2)~setFont(font) -- ... set the static text to use that font.
-- Provide for a double-click in Product icon:
self~connectStaticNotify("IDC_PRODABT_ICON_PLACE", "DBLCLK", showMsgBox)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::method showMsgBox
--say "AboutDialog-showMsgBox-01."
ans = MessageDialog(.HRSpv~AboutDblClick)
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
::method leaving
expose font image
self~deleteFont(font)
image~release()
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*============================================================================*/
/*//////////////////////////////////////////////////////////////////////////////
==============================================================================
Human-Readable Strings (HRSpv) v01-00 03Jun12
------------------------------
The HRSpv class provides constant character strings for user-visible messages.
Changes:
v00-03 11Feb12: Changed class name NRS to HRSpv
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
::CLASS HRSpv PRIVATE -- Human-Readable Strings
::CONSTANT AboutDblClick "You double-clicked!"
::CONSTANT badRatio "The new price/UOM ratio cannot be changed more than 50% up or down."
::CONSTANT closeInUpdate "Any changes made will be lost. Exit anyway?"
::CONSTANT descrTooBig "The Product Description is too long."
::CONSTANT nilSaved "Nothing was changed! Data not saved."
::CONSTANT notSaved "Changes Not Saved!"
::CONSTANT prodNameTooBig "The Product Name is too long."
::CONSTANT saved "Changes saved."
::CONSTANT uomTooBig "The new UOM is too large."
::CONSTANT uomTooSmall "The new UOM is too small."
::CONSTANT updateIP "Update in process"
::CONSTANT updateProd "Update Product"
::CONSTANT printMsg "The 'Print...' menu item is not yet implemented."
/*============================================================================*/