home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 October A / Pcwk10a98.iso / Inprise / TRIAL / JBUILDER / JSAMPLES.Z / AppDataModule.java < prev    next >
Text File  |  1998-05-08  |  111KB  |  2,314 lines

  1. /*
  2.  * Copyright (c) 1997-1998 Borland International, Inc. All Rights Reserved.
  3.  * 
  4.  * This SOURCE CODE FILE, which has been provided by Borland as part
  5.  * of a Borland product for use ONLY by licensed users of the product,
  6.  * includes CONFIDENTIAL and PROPRIETARY information of Borland.  
  7.  *
  8.  * USE OF THIS SOFTWARE IS GOVERNED BY THE TERMS AND CONDITIONS 
  9.  * OF THE LICENSE STATEMENT AND LIMITED WARRANTY FURNISHED WITH
  10.  * THE PRODUCT.
  11.  *
  12.  * IN PARTICULAR, YOU WILL INDEMNIFY AND HOLD BORLAND, ITS RELATED
  13.  * COMPANIES AND ITS SUPPLIERS, HARMLESS FROM AND AGAINST ANY CLAIMS
  14.  * OR LIABILITIES ARISING OUT OF THE USE, REPRODUCTION, OR DISTRIBUTION
  15.  * OF YOUR PROGRAMS, INCLUDING ANY CLAIMS OR LIABILITIES ARISING OUT OF
  16.  * OR RESULTING FROM THE USE, MODIFICATION, OR DISTRIBUTION OF PROGRAMS
  17.  * OR FILES CREATED FROM, BASED ON, AND/OR DERIVED FROM THIS SOURCE
  18.  * CODE FILE.
  19.  */
  20.  
  21. package borland.samples.intl.application;
  22.  
  23. import java.awt.*;
  24. import java.awt.event.*;
  25. import java.io.*;
  26. import java.sql.*;
  27. import java.text.*;
  28. import java.util.*;
  29. import borland.jbcl.layout.*;
  30. import borland.jbcl.control.*;
  31. import borland.jbcl.model.*;
  32. import borland.jbcl.dataset.*;
  33. import borland.sql.dataset.*;
  34. import borland.jbcl.util.*;
  35. import borland.jbcl.view.*;
  36.  
  37. import com.objectspace.jgl.*;
  38.  
  39. import borland.samples.intl.beans.*;
  40. import borland.samples.intl.beans.event.*;
  41.  
  42. import borland.samples.intl.application.resources.TextRes_en;
  43.  
  44. /**
  45.  * The application's data module, AppDataModule, like most data
  46.  * modules, can be conceptually divided into the following four parts:
  47.  *<p>
  48.  *  - JBCL data access components
  49.  *  - public DataSet accessor methods for use by data-aware components
  50.  *  - data module state manipulation logic
  51.  *  - application and business logic
  52.  *<p>
  53.  * The first part consists of JBCL data access components (for
  54.  * example, Database, QueryDataSet, Column, etc.) which were
  55.  * automatically added to the code and customized using the UI
  56.  * Designer.  These components are declared as instance variables
  57.  * near the top of the class definition, and are customized within
  58.  * the jbInit() method.  Some properties and custom components that
  59.  * could not be configured using the UI Designer were done in the
  60.  * AppDataModule constructor following the call to jbInit().
  61.  *<p>
  62.  * The second part of the AppDataModule consists of public DataSet
  63.  * accessor methods, such as getCustomerDataSet(), which were
  64.  * generated automatically by the UI Designer as we dropped datasets
  65.  * into the data module.  Clients of the data module use these
  66.  * accessor methods to obtain references to DataSet components
  67.  * customized within the data module.  For example, the OrderFrame frame
  68.  * uses a data-aware GridControl component to display line items for
  69.  * an order.  In order to display the line item data in the grid, we
  70.  * have to assign the OrderLineItemDataSet dataset, created in the
  71.  * data module, to be the GridControl's dataset property.  After
  72.  * compiling our data module and declaring an instance of it in
  73.  * OrderFrame, we can use the UI Designer to assign datasets
  74.  * configured in our data module to data-aware components in our
  75.  * frame.  
  76.  *<p>
  77.  * The third part of the AppDataModule consists of the methods by
  78.  * which the application's GUI components manipulate the state of the
  79.  * data module.  For example, when a user presses the "Add to Order"
  80.  * button of the ProductFrame, the button's actionPerformed handler
  81.  * invokes the AppDataModule component's addProductToOrderLineItem()
  82.  * method.  In response, the data module determines the product
  83.  * currently being viewed in the ProductFrame (the current row in the
  84.  * ProductsDataSet), and adds a new row with the appropriate
  85.  * information to the OrderLineItemDataSet.  Because the dataSet
  86.  * property of the GridControl in the OrderFrame is assigned to the
  87.  * OrderLineItemDataSet, the new row added to the OrderLineItemDataSet
  88.  * by the data module automatically becomes visible in the GridControl
  89.  * in the OrderFrame.  While it is possible to obtain references to
  90.  * datasets via the data module's dataset accessor methods and
  91.  * manipulate them directly outside the data module, maintaining a
  92.  * separation of the application's GUI and internal logic is a good
  93.  * programming practice.  Doing so helps to isolate bugs (because
  94.  * datasets will only be manipulated within the data module), and
  95.  * increases the possibility of reuse of an application's components.
  96.  * In this sample, for example, the various GUI frames are totally
  97.  * independent of the data module, dependent only upon the data
  98.  * module to implement certain order entry application behaviors
  99.  * such as moving rows from one dataset to another, or validating
  100.  * dataset data.  Thus we are free to replace the existing UI frames
  101.  * with any other frames or reuse the UI frames with another
  102.  * data module with little or no modification (and usually this
  103.  * modification can be done strictly using the UI designer).
  104.  *<p>
  105.  * The fourth part of the AppDataModule consists of methods which
  106.  * define the application's logic and business rules.  In general,
  107.  * application logic is implemented within event handlers that are
  108.  * activated in response to DataSet events.  For example, when a new
  109.  * row is inserted into the OrderDataSet, it should be given a unique
  110.  * order number.  To implement this application logic, we first used
  111.  * the UI Designer to create a row 'inserted' event handler for the
  112.  * OrderDataSet.  (When AppDataModule.java is open in the UI Designer,
  113.  * select OrderDataSet in the Component Tree, select the Events tab of
  114.  * the Inspector, and enter an event handler name for the OrderDataSet
  115.  * class's 'inserted' event property).  Inside the event handler code,
  116.  * we assign a unique value to the order_no column of the newly
  117.  * inserted row.
  118.  *<p>
  119.  * Business rules are usually defined by setting validation
  120.  * constraints on columns of a DataSet.  For example, to specify that
  121.  * the quantity of an item ordered be greater than 0, we set the min
  122.  * property of the quantity column of the OrderLineItemDataSet to the
  123.  * value '1'.  Doing so prevents a row from being posted if the
  124.  * quantity is not at least 1.
  125.  *<p>
  126.  * To allow AppDataModule to use either a JDBC database
  127.  * or a text data file as its data provider, we took advantage of the
  128.  * fact that a QueryDataSet also has a dataFile property.  Using the
  129.  * Designer, we defined both a TextDataFile and query for each
  130.  * QueryDataSet, and set the executeOnOpen property of each query to
  131.  * be false.  Doing so allows data to be provided from each
  132.  * QueryDataSet component's TextDataFile data source by default.  In order to
  133.  * use a JDBC database as the provider, we provide a static method
  134.  * (setJDBCDataSource) which sets JDBC connection information.  At
  135.  * runtime, if JDBC connection information has been set before the
  136.  * AppDataModule is instantiated, we provide data for each
  137.  * QueryDataSet by executing the query instead of loading data from a
  138.  * TextDataFile.
  139.  */
  140. public class AppDataModule implements DataModule, LocaleChangeListener {
  141.   /**
  142.    * Single instance of the AppDataModule used by the application.
  143.    * See getDataModule() for more info.
  144.    */
  145.   private static AppDataModule appDataModule = null;
  146.  
  147.   /**
  148.    * Reference to the TextRes resource bundle which contains localized
  149.    * resources for the GUI-independent side of the application.  The
  150.    * 'resource strings' wizard automatically inserts the code required
  151.    * to instantiate the resource bundle.  Once declared, we can
  152.    * then assign the bundle to resourceable objects (e.g., the
  153.    * descriptionLookupItemPainter of the orderLineItemDataSet)
  154.    * via the UI Designer.  See 
  155.    * borland\samples\intl\application\resources\TextRes.java for more
  156.    * information.
  157.    */
  158.   ResourceBundle textRes = java.util.ResourceBundle.getBundle("borland.samples.intl.application.resources.TextRes",
  159.                                                               LocaleChangeManager.getLocale());
  160.  
  161.   /**
  162.    * Determines whether the application's data sources will be all text file based
  163.    * or all JDBC database based.  It is automatically set to true
  164.    * if a JDBC data source is specified by a call to AppDataModule's
  165.    * static setJDBCDataSource() method before is
  166.    * instantiated.
  167.    */
  168.   private static boolean useQueryDataSet = false;
  169.  
  170.   /**
  171.    * Determines whether the customerNoDataSet and orderNoDataSet
  172.    * DataSets should be save back to their corresponding
  173.    * TextDataFiles.  If the user doesn't open the order form,
  174.    * these DataSets are not opened.  Saving them without opening
  175.    * them will save an empty DataSet, erasing their files.
  176.    */
  177.   private boolean saveCustomerNoDataFile = false;
  178.   private boolean saveOrderNoDataFile = false;
  179.  
  180.   /**
  181.    * Contains the URL for a JDBC database connection.  Set via the
  182.    * static setJDBCDataSource() method.
  183.    */
  184.   private static String jdbcURL;
  185.  
  186.   /**
  187.    * Contains the user name to a JDBC database connection.  Set via
  188.    * the static setJDBCDataSource() method.
  189.    */
  190.   private static String jdbcUser;
  191.  
  192.   /**
  193.    * Contains the password to a JDBC database connection.  Set via
  194.    * the static setJDBCDataSource() method.
  195.    */
  196.   private static String jdbcPassword;
  197.  
  198.   /**
  199.    * Contains the driver name for a JDBC database connection.  Set
  200.    * via the static setJDBCDataSource() method.
  201.    */
  202.   private static String jdbcDriver;
  203.  
  204.   /**
  205.    * Public constant which may be passed as the product filtering
  206.    * category argument of filterProducts() to signify that no products
  207.    * should be filtered out of ProductsDataSet.
  208.    */
  209.   public static final int NO_PRODUCT_FILTER = -1;
  210.  
  211.   /**
  212.    * Contains the value used to decide which rows to filter in/out of
  213.    * the ProductsDataSet DataSet.  See the comments for
  214.    * productDataSet_filterRow() for more information.
  215.    */
  216.   private int productFilteringCategory = NO_PRODUCT_FILTER;
  217.  
  218.   /**
  219.    * Constant used to signify that no customers should be filtered
  220.    * into customerDataSet.
  221.    */
  222.   private static int INVALID_CUSTOMER = -1;
  223.  
  224.   /**
  225.    * Holds the customer number value of the customer for the current
  226.    * order.
  227.    */
  228.   private static int queryCustomerNo = INVALID_CUSTOMER;
  229.  
  230.   /**
  231.    * Indicates whether or not a new row has already been inserted into
  232.    * OrderDataSet and CustomerDataSet in preparation for a new order
  233.    * entry.
  234.    */
  235.   protected boolean enteringOrder = false;
  236.  
  237.   /**
  238.    * Set true by localeChanged() when in the process of switching
  239.    * to a new locale.  Since switching locales requires us to 
  240.    * save and restore the pending order, dataset event listeners
  241.    * check this to see whether or not to ignore their events for
  242.    * the duration of the locale change.
  243.    */
  244.   protected boolean localeChanging = false;
  245.  
  246.   /**
  247.    * Custom (model-view) item editor for the 'quantity' column of the
  248.    * orderLineItemDataSet DataSet.  See
  249.    * borland/samples/intl/beans/IntegerSpinEditor.java for more info.
  250.    */
  251.   IntegerSpinItemEditor quantityItemEditor = new IntegerSpinItemEditor();
  252.  
  253.   /**
  254.    * Custom (model-view) item painter for the calculated 'description'
  255.    * lookup column of the orderLineItemDataSet DataSet.  See
  256.    * borland/samples/intl/beans/ResourceableItemPainter.java for
  257.    * more info.
  258.    */
  259.   ResourceableItemPainter descriptionLookupItemPainter = new ResourceableItemPainter();
  260.  
  261.   // The following AnnotatedEmptyItemPainters are custom (model-view)
  262.   // item painters used to put the 'required' message in empty,
  263.   // required columns in the orderDataSet and customerDataSet data sets.
  264.   // The following item painters were dropped into the data module
  265.   // and assigned to be item painters for columns using the UI Designer.
  266.   // The 'required' message was set as the displayString property of
  267.   // each painter via the designer.
  268.   // See borland/samples/intl/beans/AnnotatedEmptyItemPainter.java for
  269.   // more info.
  270.   AnnotatedEmptyItemPainter lastNameRequiredPainter = new AnnotatedEmptyItemPainter();
  271.   AnnotatedEmptyItemPainter firstNameRequiredPainter = new AnnotatedEmptyItemPainter();
  272.   AnnotatedEmptyItemPainter address1RequiredPainter = new AnnotatedEmptyItemPainter();
  273.   AnnotatedEmptyItemPainter cityRequiredPainter = new AnnotatedEmptyItemPainter();
  274.   AnnotatedEmptyItemPainter provinceRequiredPainter = new AnnotatedEmptyItemPainter();
  275.   AnnotatedEmptyItemPainter paymentMethodRequiredPainter = new AnnotatedEmptyItemPainter();
  276.   AnnotatedEmptyItemPainter creditCardNoRequiredPainter = new AnnotatedEmptyItemPainter();
  277.   AnnotatedEmptyItemPainter countryRequiredPainter = new AnnotatedEmptyItemPainter();
  278.  
  279.   /**
  280.    * Custom (model-view) item editors and painters for the 'size' and 'color'
  281.    * columns of the orderLineItemDataSet DataSet.  See
  282.    * borland/samples/intl/beans/ResourceablePickListItemEditor.java and
  283.    * borland/samples/intl/beans/ResourceableItemPainter.java for
  284.    * more info.
  285.    */
  286.   ResourceableItemPainter orderLineItemSizeItemPainter = new ResourceableItemPainter();
  287.   ResourceableItemPainter orderLineItemColorItemPainter = new ResourceableItemPainter();
  288.   ResourceablePickListItemEditor orderLineItemSizeItemEditor = new ResourceablePickListItemEditor();
  289.   ResourceablePickListItemEditor orderLineItemColorItemEditor = new ResourceablePickListItemEditor();
  290.  
  291.   /**
  292.    * creditCardNoItemEditor is set as the ItemEditor property of the
  293.    * creditCardNoColumn of the orderDataSet DataSet.  It is used to
  294.    * dynamically set the edit mask for entry of a credit card number.
  295.    * When the value of the credit card name column changes, its column
  296.    * value change listener updates creditCardNoItemEditor's edit mask.
  297.    */
  298.   MaskableTextItemEditor creditCardNoItemEditor = new MaskableTextItemEditor();
  299.  
  300.   // The following components were added to the data module
  301.   // automatically by the UI Designer when we dropped data access
  302.   // components into the data module.
  303.   Database database = new Database();
  304.   TextDataFile customerDataFile = new TextDataFile();
  305.  
  306.   /**
  307.    * DataSet used to access customer data from either customerDataFile
  308.    * or a query on the Customers table.  It is row filtered to only
  309.    * include the single customer row which should be visible/editable
  310.    * at any time.
  311.    */
  312.   QueryDataSet customerDataSet = new QueryDataSet();
  313.   Column lastNameColumn = new Column();
  314.   Column middleNameColumn = new Column();
  315.   Column firstNameColumn = new Column();
  316.   Column address1Column = new Column();
  317.   Column address2Column = new Column();
  318.   Column customerNoColumn = new Column();
  319.   Column cityColumn = new Column();
  320.   Column provinceColumn = new Column();
  321.   Column countryColumn = new Column();
  322.   Column emailColumn = new Column();
  323.   Column phoneColumn = new Column();
  324.   Column faxColumn = new Column();
  325.   Column passwordColumn = new Column();
  326.   Column postalCodeColumn = new Column();
  327.  
  328.   /**
  329.    * DataSetView which uses customerDataSet as its StorageDataSet.
  330.    * Unlike customerDataSet, it is not restricted to viewing only a
  331.    * single row of the customerDataSet, and therefore is used in
  332.    * CustomerLookupDialog.java as the DataSet of a GridControl which
  333.    * shows the entire list of customers.
  334.    */
  335.   DataSetView customerDataSetView = new DataSetView();
  336.  
  337.   TextDataFile exchangeRateDataFile = new TextDataFile();
  338.   
  339.   QueryDataSet exchangeRateDataSet = new QueryDataSet();
  340.   Column exchangeRateColumn = new Column();
  341.  
  342.   TextDataFile paymentMethodDataFile = new TextDataFile();
  343.  
  344.   QueryDataSet paymentMethodDataSet = new QueryDataSet();
  345.   
  346.   TextDataFile orderDataFile = new TextDataFile();
  347.  
  348.   QueryDataSet orderDataSet = new QueryDataSet();
  349.   Column orderDateColumn = new Column();
  350.   Column paymentMethodColumn = new Column();
  351.   Column creditCardNoColumn = new Column();
  352.   Column cardExpirationDateColumn = new Column();
  353.  
  354.   TextDataFile orderLineItemDataFile = new TextDataFile();
  355.  
  356.   QueryDataSet orderLineItemDataSet = new QueryDataSet();
  357.   Column skuColumn = new Column();
  358.   Column quantityColumn = new Column();
  359.   Column sizeColumn = new Column();
  360.   Column colorColumn = new Column();
  361.   Column descriptionLookupColumn = new Column();
  362.   Column unitPriceLineItemColumn = new Column();
  363.   Column extdPriceColumn = new Column();
  364.   Column localExtdPriceColumn = new Column();
  365.   Column subtotalColumn = new Column();
  366.   Column localSubtotalColumn = new Column();
  367.   Column shippingColumn = new Column();
  368.   Column localShippingColumn = new Column();
  369.   Column taxColumn = new Column();
  370.   Column localTaxColumn = new Column();
  371.   Column totalColumn = new Column();
  372.   Column localTotalColumn = new Column();
  373.  
  374.   TextDataFile productsDataFile = new TextDataFile();
  375.  
  376.   QueryDataSet productsDataSet = new QueryDataSet();
  377.   Column descriptionColumn = new Column();
  378.   Column unitPriceProductsColumn = new Column();
  379.   
  380.   TextDataFile productColorsDataFile = new TextDataFile();
  381.  
  382.   QueryDataSet productColorsDataSet = new QueryDataSet();
  383.  
  384.   TextDataFile productSizesDataFile = new TextDataFile();
  385.  
  386.   QueryDataSet productSizesDataSet = new QueryDataSet();
  387.  
  388.   TextDataFile customerNoDataFile = new TextDataFile();
  389.  
  390.   QueryDataSet customerNoDataSet = new QueryDataSet();
  391.  
  392.   TextDataFile orderNoDataFile = new TextDataFile();
  393.  
  394.   QueryDataSet orderNoDataSet = new QueryDataSet();
  395.   Column imageColumn = new Column();
  396.   Column orderNoColumn = new Column();
  397.   Column orderLineItemNoColumn = new Column();
  398.   Column totalQuantityColumn = new Column();
  399.  
  400.   /**
  401.    * Initializes data-access components of the data module.  
  402.    * Components configurable via the UI Designer are set within jbInit(),
  403.    * all others are set in the code following the call to jbInit().
  404.    */
  405.   public AppDataModule() {
  406.     try {
  407.       jbInit();
  408.  
  409.       // The remaining code configures column properties and
  410.       // initializes DataSets in ways which could not be done using
  411.       // the UI Designer.
  412.  
  413.       // If setJDBCDataSource() was called prior to initial
  414.       // instantiation of the AppDataModule, useQueryDataSet will have
  415.       // the value 'true' and we will try to use its passed parameters
  416.       // to load data from a JDBC source.
  417.  
  418.       if (useQueryDataSet) {
  419.         // Explicitly load the JDBC Driver
  420.         Class.forName(jdbcDriver);
  421.         // Don't pass a driver to ConnectionDescriptor because it will lookup
  422.         // the system classpath property (causing an applet security violation) to
  423.         // locate the driver.
  424.         database.setConnection(new borland.sql.dataset.ConnectionDescriptor(jdbcURL, jdbcUser, jdbcPassword, false, ""));
  425.       }
  426.  
  427.       // Set aggregation descriptors for aggregated columns (columns
  428.       // for which the calcType property is CalcType.AGGREGATE).
  429.       // The first argument to the AggDescriptor is the list
  430.       // of columns on which to group.  Since we want to compute the
  431.       // sum of values for rows in the orderLineItemDataSet (the
  432.       // line item rows for each order), we specify the linking
  433.       // column 'order_no' as the grouping column.  
  434.       // The following AggDescriptor specifies that 
  435.       // SumAggOperator() should be applied to the 'extd_price' value
  436.       // in all rows of the orderLineItemDataSet grouped by 'order_no', and
  437.       // the aggregated result assigned to subtotal.
  438.       // In JBuilder 2.0 or later, this property can be set from within the UI designer.
  439.       subtotalColumn.setAgg(new AggDescriptor(new String [] { "order_no" }, "extd_price", new SumAggOperator()));
  440.  
  441.       // The following AggDescriptor specifies that the
  442.       // SumAggOperator() should be applied to the 'quantity' value in
  443.       // all rows of the orderLineItemDataSet grouped by 'order_no' and the
  444.       // aggregated result assigned to the totalQuantityColumn.
  445.       // In JBuilder 2.0 or later, this property can be set from within the UI designer.
  446.       totalQuantityColumn.setAgg(new AggDescriptor(new String [] { "order_no" }, "quantity", new SumAggOperator()));
  447.  
  448.       // Set aggregation descriptors for columns whose values
  449.       // are based on calculations performed on
  450.       // aggregated values.  The calcType property of a 'custom' aggregated
  451.       // column must be set to CalcType.AGGREGATE.  An AggDescriptor
  452.       // for a calculated aggregated column differs from an
  453.       // AggDescriptor for a regular aggregated column in that an
  454.       // aggregate operator and aggregate value column name are both
  455.       // set to 'null'.  When a custom aggregate value must be
  456.       // recalculated, the CalcAggFieldsListener registered with
  457.       // the data set is automatically invoked.
  458.       // In JBuilder 2.0 or later, these properties can be set from within the UI designer.
  459.       localSubtotalColumn.setAgg(new AggDescriptor(new String [] { "order_no" }, null, null));
  460.       shippingColumn.setAgg(new AggDescriptor(new String [] { "order_no" }, null, null));
  461.       localShippingColumn.setAgg(new AggDescriptor(new String [] { "order_no" }, null, null));
  462.       taxColumn.setAgg(new AggDescriptor(new String [] { "order_no" }, null, null));
  463.       localTaxColumn.setAgg(new AggDescriptor(new String [] { "order_no" }, null, null));
  464.       totalColumn.setAgg(new AggDescriptor(new String [] { "order_no" }, null, null));
  465.       localTotalColumn.setAgg(new AggDescriptor(new String [] { "order_no" }, null, null));
  466.  
  467.       // Set localized display masks for date and currency columns of
  468.       // the orderDataSet for the default locale.  If a locale change
  469.       // occurs, code within localeChanged() will reset the masks for
  470.       // the new locale.
  471.       orderDateColumn.setDisplayMask(((SimpleDateFormat) SimpleDateFormat.getDateInstance(DateFormat.DEFAULT, LocaleChangeManager.getLocale())).toPattern());
  472.  
  473.       // Temporary workaround for bug in JDK 1.1.6, namely that currency patterns for some
  474.       // locales throw exceptions when analyzed by java.text.DecimalFormat().
  475.       if (LocaleChangeManager.getLocale().equals(Locale.ITALY) ||
  476.           LocaleChangeManager.getLocale().getCountry().equals("CH")) {
  477.         localExtdPriceColumn.setDisplayMask(null);
  478.         localSubtotalColumn.setDisplayMask(null);
  479.         localShippingColumn.setDisplayMask(null);
  480.         localTaxColumn.setDisplayMask(null);
  481.         localTotalColumn.setDisplayMask(null);
  482.       } else {
  483.         localExtdPriceColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  484.         localSubtotalColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  485.         localShippingColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  486.         localTaxColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  487.         localTotalColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  488.       }
  489.       
  490.       // Provide an edit mask which allows the user to only enter the
  491.       // month and year for a credit card's expiration date.  When
  492.       // using such an edit mask, the day is automatically set to the
  493.       // first of the month.  Thus we set the minimum date for the
  494.       // credit card expiration column to be the last day of the
  495.       // previous month.
  496.       // Note that we could have set the minimum value via the
  497.       // designer as a string.  However, we would have to provide
  498.       // the string in the proper format for the runtime
  499.       // locale (which could vary).  A variant allows us to set the 
  500.       // minimum value independently of our runtime locale.
  501.       Variant variant = new Variant();
  502.       Calendar calendar = new GregorianCalendar();
  503.       variant.setTimestamp(new java.sql.Timestamp(calendar.get(Calendar.YEAR)-1900, calendar.get(Calendar.MONTH), 1, 0, 0, 0, 0));
  504.       cardExpirationDateColumn.setMinValue(variant);
  505.  
  506.       // Adds a row filter listener to the picklist item editors used to
  507.       // show a list of sizes and colors for a product in orderLineItemDataSet.
  508.       // We use these filters to 'filter in' only the sizes or colors
  509.       // appropriate for the current product line item.
  510.       orderLineItemSizeItemEditor.addRowFilterListener(new AppDataModule_orderLineItemSizeItemEditor_rowFilterAdapter(this));
  511.       orderLineItemColorItemEditor.addRowFilterListener(new AppDataModule_orderLineItemColorItemEditor_rowFilterAdapter(this));
  512.  
  513.       if (useQueryDataSet) {
  514.         // The following query is used for two different purposes.
  515.         // First, we pass it a non-existent customer_no to provide an empty set of order
  516.         // rows into orderDataSet and orderLineItemDataSet.  We then insert new 
  517.         // rows into the data sets.  By doing the query, even though it
  518.         // retrieves no rows, we load the metadata info into the DataSet, so that we
  519.         // can resolve it back to the data source using DataSet.saveChanges(DataSet).
  520.         // Second, this query is also used to select all of a customer's orders for
  521.         // browsing.  Since we don't allow a customer to make any changes to existing
  522.         // orders, resolving is not necessary in this case.
  523.         ParameterRow orderDataSetQueryParameters = new ParameterRow();
  524.         orderDataSetQueryParameters.addColumn("customer_no", Variant.INT);
  525.         orderDataSetQueryParameters.setInt("customer_no", queryCustomerNo);
  526.         orderDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from orders where customer_no = :customer_no", orderDataSetQueryParameters, false, Load.ALL));
  527.       } else {
  528.  
  529.         // When using a QueryDataSet, we simply execute a query to provide order rows
  530.         // into the orderDataSet when browsing a customer's previous orders.
  531.         // But for a text data file source, we always have all order rows in the
  532.         // data set.  To restrict the user to navigating only a particular customer's 
  533.         // order data, we add a row filter and restrict navigation to order rows for 
  534.         // the current customer (stored in the queryCustomerNo variable).
  535.         orderDataSet.addRowFilterListener(new AppDataModule_orderDataSet_rowFilterAdapter(this));
  536.       }
  537.  
  538.       // Provide data set data from the appropriate data sources.
  539.       if (useQueryDataSet) {
  540.         // If we're using QueryDataSets, we first need to set the LoadOnOpen property of each
  541.         // DataSet's corresponding TextDataFile to false, so that opening the DataSet will
  542.         // not load data from the TextDataFile.  Then in order to provide data from the
  543.         // JDBC data provider, we execute the query.
  544.         customerDataFile.setLoadOnOpen(false);
  545.         customerDataSet.executeQuery();
  546.         customerDataSet.open();
  547.         exchangeRateDataFile.setLoadOnOpen(false);
  548.         exchangeRateDataSet.executeQuery();
  549.         exchangeRateDataSet.open();
  550.         paymentMethodDataFile.setLoadOnOpen(false);
  551.         paymentMethodDataSet.executeQuery();
  552.         paymentMethodDataSet.open();
  553.         orderDataFile.setLoadOnOpen(false);
  554.         orderDataSet.executeQuery();
  555.         orderDataSet.open();
  556.         orderLineItemDataFile.setLoadOnOpen(false);
  557.         orderLineItemDataSet.executeQuery();
  558.         orderLineItemDataSet.open();
  559.         productsDataFile.setLoadOnOpen(false);
  560.         productsDataSet.executeQuery();
  561.         productsDataSet.open();
  562.         productColorsDataFile.setLoadOnOpen(false);
  563.         productColorsDataSet.executeQuery();
  564.         productColorsDataSet.open();
  565.         productSizesDataFile.setLoadOnOpen(false);
  566.         productSizesDataSet.executeQuery();
  567.         productSizesDataSet.open();
  568.         customerNoDataFile.setLoadOnOpen(false);
  569.         orderNoDataFile.setLoadOnOpen(false);
  570.       } else {
  571.         // Open the DataSets we plan to use in subsequent operations.
  572.         // When using a TextDataFile, the default value for the 'loadOnOpen'
  573.         // property is true, so opening the data set will automatically load
  574.         // data from the text file.
  575.         customerDataSet.open();
  576.         exchangeRateDataSet.open();
  577.         paymentMethodDataSet.open();
  578.         orderDataSet.open();
  579.         orderLineItemDataSet.open();
  580.         productsDataSet.open();
  581.         productColorsDataSet.open();
  582.         productSizesDataSet.open();
  583.       }
  584.  
  585.       customerDataSetView.open();
  586.  
  587.       // Now that the paymentMethodDataSet is open, set the default
  588.       // credit card name and corresponding card no digit edit mask
  589.       // from the paymentMethodDataSet.
  590.       creditCardNoItemEditor.setEditMask(paymentMethodDataSet.getString("digit_pattern"), Variant.STRING, LocaleChangeManager.getLocale());
  591.  
  592.  
  593.       // Because descriptions for products in the productsDataSet are localized,
  594.       // we provide a value for the productDataSet's 'description' column by
  595.       // using a product's 'sku' number as its lookup key in a resource bundle.
  596.       // We then add that value into the 'description' column.
  597.       // When using a TextDataFile data source, we also need to explicitly
  598.       // fill the 'image' column with image data, since binary data cannot be
  599.       // stored in a text file.
  600.       int sku;
  601.       String imageFileName;
  602.       String localizedDescription;
  603.  
  604.       // Iterate over all rows in productsDataSet 
  605.       productsDataSet.first();
  606.       while (productsDataSet.inBounds()) {
  607.         sku = productsDataSet.getInt("sku");
  608.  
  609.         // Add localized description data
  610.         localizedDescription = textRes.getString("" + sku);
  611.         productsDataSet.setString("description", localizedDescription);
  612.  
  613.         // Since we can't save binary image data within a text data
  614.         // file, when using a text data file as our data source we
  615.         // need to import the image data separately.
  616.         if (!useQueryDataSet) {
  617.           imageFileName = "data\\" + sku + ".gif";
  618.           BufferedInputStream bufferedInputStream = 
  619.             new BufferedInputStream(this.getClass().getResourceAsStream(imageFileName));
  620.           bufferedInputStream.mark(40000);
  621.           productsDataSet.setInputStream("image", bufferedInputStream);
  622.         }
  623.         productsDataSet.next();
  624.       }
  625.       // Since productsDataSet.next() will fail on the last row
  626.       // (allowing us to exit the loop), we need to explicitly post
  627.       // changes which would have been posted had it been successful.
  628.       productsDataSet.post();
  629.       productsDataSet.first();
  630.  
  631.       // Load the current US dollar exchange rate our of exchangeRateDataSet
  632.       readExchangeRate();
  633.  
  634.       // Register ourselves as a locale change listener with the system locale change manager
  635.       LocaleChangeManager.getLocaleChangeManager().addLocaleChangeListener(this);
  636.  
  637.       // Install a custom DataSetException error handler to display localized messages
  638.       DataSetException.addExceptionListener(new ResourcedDataSetExceptionHandler(this));
  639.     }
  640.     catch (Exception e) {
  641.       borland.jbcl.util.Diagnostic.printStackTrace(e);
  642.     }
  643.   }
  644.  
  645.   /**
  646.    * Contains components customized using the UI Designer.
  647.    */
  648.   void jbInit() throws Exception{
  649.     lastNameColumn.setCaption(textRes.getString("last_name"));
  650.     lastNameColumn.setColumnName("last_name");
  651.     lastNameColumn.setDataType(borland.jbcl.util.Variant.STRING);
  652.     lastNameColumn.setEditMask("cccccccccccccccccccccccccccccc");
  653.     lastNameColumn.setItemPainter(lastNameRequiredPainter);
  654.     lastNameColumn.setRequired(true);
  655.     middleNameColumn.setCaption(textRes.getString("middle_name"));
  656.     middleNameColumn.setColumnName("middle_name");
  657.     middleNameColumn.setDataType(borland.jbcl.util.Variant.STRING);
  658.     middleNameColumn.setEditMask("cccccccccccccccccccccccccccccc");
  659.     firstNameColumn.setCaption(textRes.getString("first_name"));
  660.     firstNameColumn.setColumnName("first_name");
  661.     firstNameColumn.setDataType(borland.jbcl.util.Variant.STRING);
  662.     firstNameColumn.setEditMask("cccccccccccccccccccccccccccccc");
  663.     firstNameColumn.setItemPainter(firstNameRequiredPainter);
  664.     firstNameColumn.setRequired(true);
  665.     address1Column.setCaption(textRes.getString("address1"));
  666.     address1Column.setColumnName("address1");
  667.     address1Column.setDataType(borland.jbcl.util.Variant.STRING);
  668.     address1Column.setEditMask("cccccccccccccccccccccccccccccccccccccccccccccccccc");
  669.     address1Column.setVisible(borland.jbcl.util.TriState.NO);
  670.     address1Column.setItemPainter(address1RequiredPainter);
  671.     address1Column.setRequired(true);
  672.     address2Column.setCaption(textRes.getString("address2"));
  673.     address2Column.setColumnName("address2");
  674.     address2Column.setDataType(borland.jbcl.util.Variant.STRING);
  675.     address2Column.setEditMask("cccccccccccccccccccccccccccccccccccccccccccccccccc");
  676.     address2Column.setVisible(borland.jbcl.util.TriState.NO);
  677.     customerNoColumn.setColumnName("customer_no");
  678.     customerNoColumn.setDataType(borland.jbcl.util.Variant.INT);
  679.     customerNoColumn.setVisible(borland.jbcl.util.TriState.NO);
  680.     cityColumn.setCaption(textRes.getString("city"));
  681.     cityColumn.setColumnName("city");
  682.     cityColumn.setDataType(borland.jbcl.util.Variant.STRING);
  683.     cityColumn.setEditMask("cccccccccccccccccccccccccccccc");
  684.     cityColumn.setItemPainter(cityRequiredPainter);
  685.     cityColumn.setRequired(true);
  686.     provinceColumn.setCaption(textRes.getString("province"));
  687.     provinceColumn.setColumnName("province");
  688.     provinceColumn.setDataType(borland.jbcl.util.Variant.STRING);
  689.     provinceColumn.setEditMask(textRes.getString("province_editmask"));
  690.     provinceColumn.setItemPainter(provinceRequiredPainter);
  691.     countryColumn.setCaption(textRes.getString("country"));
  692.     countryColumn.setColumnName("country");
  693.     countryColumn.setDataType(borland.jbcl.util.Variant.STRING);
  694.     countryColumn.setEditMask("cccccccccccccccccccccccccccccc");
  695.     countryColumn.setItemPainter(countryRequiredPainter);
  696.     countryColumn.setRequired(true);
  697.     emailColumn.setCaption(textRes.getString("e_mail"));
  698.     emailColumn.setColumnName("e_mail");                                    
  699.     emailColumn.setDataType(borland.jbcl.util.Variant.STRING);
  700.     emailColumn.setEditMask("cccccccccccccccccccccccccccccccccccccccccccccccccc");
  701.     emailColumn.setVisible(borland.jbcl.util.TriState.NO);
  702.     phoneColumn.setCaption(textRes.getString("phone"));
  703.     phoneColumn.setColumnName("phone");
  704.     phoneColumn.setDataType(borland.jbcl.util.Variant.STRING);
  705.     phoneColumn.setEditMask(textRes.getString("phone_editmask"));
  706.     phoneColumn.setVisible(borland.jbcl.util.TriState.NO);
  707.     faxColumn.setCaption(textRes.getString("fax"));
  708.     faxColumn.setColumnName("fax");
  709.     faxColumn.setDataType(borland.jbcl.util.Variant.STRING);
  710.     faxColumn.setEditMask(textRes.getString("phone_editmask"));
  711.     faxColumn.setVisible(borland.jbcl.util.TriState.NO);
  712.     passwordColumn.setColumnName("mangled_password");
  713.     passwordColumn.setDataType(borland.jbcl.util.Variant.STRING);
  714.     passwordColumn.setVisible(borland.jbcl.util.TriState.NO);
  715.     postalCodeColumn.setCaption(textRes.getString("postal_code"));
  716.     postalCodeColumn.setColumnName("postal_code");                    
  717.     postalCodeColumn.setDataType(borland.jbcl.util.Variant.STRING);
  718.     postalCodeColumn.setEditMask(textRes.getString("postal_code_editmask"));
  719.     customerDataSetView.setStorageDataSet(customerDataSet);
  720. //  In JBuilder 2.0, the following path was changed to a relative path rather than
  721. //  an absolute one, so that it would not be necessary to replace 'JBuilder2' with
  722. //  the actual JBuilder 2.0 installation directory in order to simply run the sample.
  723. //  When this data module is designed in the designer however, the following text
  724. //  file cannot be found because the relative path is incorrect relative to the
  725. //  location of the data module.  In order to design this data module in the UI designer with all 
  726. //  columns (not only the persistent ones) from the text data files, uncomment and
  727. //  edit, if necessary, the line with the absolute path, and comment out the
  728. //  line with the relative path.  Repeat the process for all other similarly
  729. //  commented out lines below.
  730. //    exchangeRateDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\ExchangeRates.txt");
  731.     exchangeRateDataFile.setFileName("application\\data\\ExchangeRates.txt");
  732.     exchangeRateDataSet.setDataFile(exchangeRateDataFile);
  733.     exchangeRateDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from exchangeRates", null, false, Load.ALL));
  734.     exchangeRateColumn.setColumnName("exchange_rate");
  735.     exchangeRateColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  736.     exchangeRateColumn.setEditMask("#####{.#####}");
  737.     exchangeRateColumn.addColumnChangeListener(new AppDataModule_exchangeRateColumn_columnChangeAdapter(this));
  738. //    paymentMethodDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\PaymentMethods.txt");
  739.     paymentMethodDataFile.setFileName("application\\data\\PaymentMethods.txt");
  740.     paymentMethodDataSet.setDataFile(paymentMethodDataFile);
  741.     paymentMethodDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from paymentMethods", null, false, Load.ALL));
  742. //    orderDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\Orders.txt");
  743.     orderDataFile.setFileName("application\\data\\Orders.txt");
  744.     orderDataSet.setDataFile(orderDataFile);
  745.     orderDataSet.setEnableInsert(false);
  746.     orderDataSet.setEnableDelete(false);
  747.     orderDataSet.addEditListener(new AppDataModule_orderDataSet_editAdapter(this));
  748.     orderDateColumn.setColumnName("order_date");
  749.     orderDateColumn.setDataType(borland.jbcl.util.Variant.TIMESTAMP);
  750.     orderDateColumn.setEditable(false);
  751.     orderDateColumn.setDefault("NOW");
  752.     paymentMethodColumn.setColumnName("payment_method");
  753.     paymentMethodColumn.setDataType(borland.jbcl.util.Variant.STRING);
  754.     paymentMethodColumn.setItemPainter(paymentMethodRequiredPainter);
  755.     paymentMethodColumn.setPickList(new borland.jbcl.dataset.PickListDescriptor(paymentMethodDataSet, new String[] {"CREDIT_CARD_NAME"}, new String[] {"CREDIT_CARD_NAME"}, new String[] {"PAYMENT_METHOD"}, false));
  756.     paymentMethodColumn.setRequired(true);
  757.     paymentMethodColumn.addColumnChangeListener(new AppDataModule_paymentMethodColumn_columnChangeAdapter(this));
  758.     cardExpirationDateColumn.setColumnName("card_expiration_date");
  759.     cardExpirationDateColumn.setDataType(borland.jbcl.util.Variant.TIMESTAMP);
  760.     cardExpirationDateColumn.setEditMask(textRes.getString("month_year_editmask"));
  761.     cardExpirationDateColumn.setDisplayMask(textRes.getString("month_year_editmask"));
  762.     cardExpirationDateColumn.setRequired(true);
  763.     creditCardNoColumn.setColumnName("credit_card_no");
  764.     creditCardNoColumn.setDataType(borland.jbcl.util.Variant.STRING);
  765.     creditCardNoColumn.setItemPainter(creditCardNoRequiredPainter);
  766.     creditCardNoColumn.setItemEditor(creditCardNoItemEditor);
  767.     creditCardNoColumn.setRequired(true);
  768. //    orderLineItemDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\OrderLineItems.txt");
  769.     orderLineItemDataFile.setFileName("application\\data\\OrderLineItems.txt");
  770.     orderLineItemDataSet.setDataFile(orderLineItemDataFile);
  771.     orderLineItemDataSet.setMasterLink(new borland.jbcl.dataset.MasterLinkDescriptor(orderDataSet, new String[] {"order_no"}, new String[] {"order_no"}, false));
  772.     orderLineItemDataSet.setEnableInsert(false);
  773.     orderLineItemDataSet.setEnableDelete(false);
  774.     orderLineItemDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from orderLineItems", null, false, Load.ALL));
  775.     orderLineItemDataSet.addCalcAggFieldsListener(new AppDataModule_orderLineItemDataSet_calcAggFieldsAdapter(this));
  776.     orderLineItemDataSet.addCalcFieldsListener(new AppDataModule_orderLineItemDataSet_calcFieldsAdapter(this));
  777.     quantityColumn.setCaption(textRes.getString("quantity"));
  778.     quantityColumn.setColumnName("quantity");
  779.     quantityColumn.setDataType(borland.jbcl.util.Variant.INT);
  780.     quantityColumn.setItemEditor(quantityItemEditor);
  781.     quantityColumn.setMin("1");
  782.     quantityColumn.addColumnChangeListener(new AppDataModule_quantityColumn_columnChangeAdapter(this));
  783.     sizeColumn.setCaption(textRes.getString("size"));
  784.     sizeColumn.setColumnName("sizes");
  785.     sizeColumn.setDataType(borland.jbcl.util.Variant.STRING);
  786.     sizeColumn.setItemEditor(orderLineItemSizeItemEditor);
  787.     sizeColumn.setItemPainter(orderLineItemSizeItemPainter);
  788.     sizeColumn.setPickList(new borland.jbcl.dataset.PickListDescriptor(productSizesDataSet, new String[] {"AVAILABLE_SIZES"}, new String[] {"AVAILABLE_SIZES"}, new String[] {"SIZES"}, false));
  789.     colorColumn.setCaption(textRes.getString("color"));
  790.     colorColumn.setColumnName("colors");
  791.     colorColumn.setDataType(borland.jbcl.util.Variant.STRING);
  792.     colorColumn.setItemEditor(orderLineItemColorItemEditor);
  793.     colorColumn.setItemPainter(orderLineItemColorItemPainter);
  794.     colorColumn.setPickList(new borland.jbcl.dataset.PickListDescriptor(productColorsDataSet, new String[] {"AVAILABLE_COLORS"}, new String[] {"AVAILABLE_COLORS"}, new String[] {"COLORS"}, false));
  795.     descriptionLookupColumn.setCaption(textRes.getString("description"));
  796.     descriptionLookupColumn.setColumnName("description");
  797.     descriptionLookupColumn.setResolvable(false);
  798.     descriptionLookupColumn.setCalcType(borland.jbcl.dataset.CalcType.CALC);
  799.     descriptionLookupColumn.setDataType(borland.jbcl.util.Variant.STRING);
  800.     descriptionLookupColumn.setItemPainter(descriptionLookupItemPainter);
  801.     descriptionLookupColumn.setEditable(false);
  802.     unitPriceLineItemColumn.setCaption(textRes.getString("unit_price"));
  803.     unitPriceLineItemColumn.setCurrency(true);
  804.     unitPriceLineItemColumn.setColumnName("unit_price");
  805.     unitPriceLineItemColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  806.     unitPriceLineItemColumn.setLocale(new java.util.Locale("en", "US", ""));
  807.     unitPriceLineItemColumn.setEditable(false);
  808.     extdPriceColumn.setCaption(textRes.getString("extd_price"));
  809.     extdPriceColumn.setCalcType(borland.jbcl.dataset.CalcType.CALC);
  810.     extdPriceColumn.setCurrency(true);
  811.     extdPriceColumn.setColumnName("extd_price");
  812.     extdPriceColumn.setResolvable(false);
  813.     extdPriceColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  814.     extdPriceColumn.setLocale(new java.util.Locale("en", "US", ""));
  815.     localExtdPriceColumn.setCaption(textRes.getString("local_price"));
  816.     localExtdPriceColumn.setCalcType(borland.jbcl.dataset.CalcType.CALC);
  817.     localExtdPriceColumn.setColumnName("local_extd_price");
  818.     localExtdPriceColumn.setResolvable(false);
  819.     localExtdPriceColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  820.     subtotalColumn.setCalcType(borland.jbcl.dataset.CalcType.AGGREGATE);
  821.     subtotalColumn.setCurrency(true);
  822.     subtotalColumn.setColumnName("subtotal");
  823.     subtotalColumn.setResolvable(false);
  824.     subtotalColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  825.     subtotalColumn.setLocale(new java.util.Locale("en", "US", ""));
  826.     localSubtotalColumn.setCalcType(borland.jbcl.dataset.CalcType.AGGREGATE);
  827.     localSubtotalColumn.setColumnName("local_subtotal");
  828.     localSubtotalColumn.setResolvable(false);
  829.     localSubtotalColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  830.     shippingColumn.setCalcType(borland.jbcl.dataset.CalcType.AGGREGATE);
  831.     shippingColumn.setCurrency(true);
  832.     shippingColumn.setColumnName("shipping");
  833.     shippingColumn.setResolvable(false);
  834.     shippingColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  835.     shippingColumn.setLocale(new java.util.Locale("en", "US", ""));
  836.     localShippingColumn.setCalcType(borland.jbcl.dataset.CalcType.AGGREGATE);
  837.     localShippingColumn.setColumnName("local_shipping");
  838.     localShippingColumn.setResolvable(false);
  839.     localShippingColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  840.     taxColumn.setCalcType(borland.jbcl.dataset.CalcType.AGGREGATE);
  841.     taxColumn.setCurrency(true);
  842.     taxColumn.setColumnName("tax");
  843.     taxColumn.setResolvable(false);
  844.     taxColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  845.     taxColumn.setLocale(new java.util.Locale("en", "US", ""));
  846.     localTaxColumn.setCalcType(borland.jbcl.dataset.CalcType.AGGREGATE);
  847.     localTaxColumn.setCurrency(true);
  848.     localTaxColumn.setColumnName("local_tax");
  849.     localTaxColumn.setResolvable(false);
  850.     localTaxColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  851.     totalColumn.setCalcType(borland.jbcl.dataset.CalcType.AGGREGATE);
  852.     totalColumn.setCurrency(true);
  853.     totalColumn.setColumnName("total");
  854.     totalColumn.setResolvable(false);
  855.     totalColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  856.     totalColumn.setLocale(new java.util.Locale("en", "US", ""));
  857.     localTotalColumn.setCalcType(borland.jbcl.dataset.CalcType.AGGREGATE);
  858.     localTotalColumn.setColumnName("local_total");
  859.     localTotalColumn.setResolvable(false);
  860.     localTotalColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  861.     skuColumn.setCaption(textRes.getString("sku"));
  862.     skuColumn.setColumnName("sku");
  863.     skuColumn.setDataType(borland.jbcl.util.Variant.INT);
  864.     skuColumn.setEditable(false);
  865. //    productsDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\Products.txt");
  866.     productsDataFile.setFileName("application\\data\\Products.txt");
  867.     unitPriceProductsColumn.setCurrency(true);
  868.     unitPriceProductsColumn.setColumnName("unit_price");
  869.     unitPriceProductsColumn.setDataType(borland.jbcl.util.Variant.DOUBLE);
  870.     unitPriceProductsColumn.setLocale(new java.util.Locale("en", "US", ""));
  871.     descriptionColumn.setColumnName("description");
  872.     descriptionColumn.setDataType(borland.jbcl.util.Variant.STRING);
  873.     productsDataSet.setDataFile(productsDataFile);
  874.     productsDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from products", null, false, Load.ALL));
  875.     productsDataSet.addRowFilterListener(new AppDataModule_productsDataSet_rowFilterAdapter(this));
  876. //    productColorsDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\ProductColors.txt");
  877.     productColorsDataFile.setFileName("application\\data\\ProductColors.txt");
  878.     productColorsDataSet.setDataFile(productColorsDataFile);
  879.     productColorsDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from productColors", null, false, Load.ALL));
  880. //    productSizesDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\ProductSizes.txt");
  881.     productSizesDataFile.setFileName("application\\data\\ProductSizes.txt");
  882.     productSizesDataSet.setDataFile(productSizesDataFile);
  883.     productSizesDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from productSizes", null, false, Load.ALL));
  884.     customerNoDataSet.setDataFile(customerNoDataFile);
  885.     customerNoDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from customerNo", null, false, Load.ALL));
  886. //    customerNoDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\CustomerNo.txt");
  887.     customerNoDataFile.setFileName("application\\data\\CustomerNo.txt");
  888. //    orderNoDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\OrderNo.txt");
  889.     orderNoDataFile.setFileName("application\\data\\OrderNo.txt");
  890.     orderNoDataSet.setDataFile(orderNoDataFile);
  891.     orderNoDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from orderNo ", null, false, Load.ALL));
  892.     imageColumn.setColumnName("image");
  893.     imageColumn.setDataType(borland.jbcl.util.Variant.INPUTSTREAM);
  894.     imageColumn.setEditable(false);
  895.     orderNoColumn.setColumnName("order_no");
  896.     orderNoColumn.setDataType(borland.jbcl.util.Variant.INT);
  897.     orderLineItemNoColumn.setColumnName("order_no");
  898.     orderLineItemNoColumn.setDataType(borland.jbcl.util.Variant.INT);
  899.     totalQuantityColumn.setCalcType(borland.jbcl.dataset.CalcType.AGGREGATE);
  900.     totalQuantityColumn.setColumnName("total_quantity");
  901.     totalQuantityColumn.setDataType(borland.jbcl.util.Variant.INT);
  902.     totalQuantityColumn.setResolvable(false);
  903. //    customerDataFile.setFileName("\\JBuilder2\\samples\\borland\\samples\\intl\\application\\data\\Customers.txt");
  904.     customerDataFile.setFileName("application\\data\\Customers.txt");
  905.     customerDataSet.setDataFile(customerDataFile);
  906.     customerDataSet.setEnableInsert(false);
  907.     customerDataSet.setEnableDelete(false);
  908.     customerDataSet.setQuery(new borland.sql.dataset.QueryDescriptor(database, "select * from customers", null, false, Load.ALL));
  909.     customerDataSet.addRowFilterListener(new AppDataModule_customerDataSet_rowFilterAdapter(this));
  910.     customerDataSet.addEditListener(new AppDataModule_customerDataSet_editAdapter(this));
  911.     descriptionLookupItemPainter.setResourceBundle(textRes);
  912.     orderLineItemSizeItemPainter.setResourceBundle(textRes);
  913.     orderLineItemColorItemPainter.setResourceBundle(textRes);
  914.     lastNameRequiredPainter.setDisplayString(textRes.getString("value_required"));
  915.     firstNameRequiredPainter.setDisplayString(textRes.getString("value_required"));
  916.     address1RequiredPainter.setDisplayString(textRes.getString("value_required"));
  917.     cityRequiredPainter.setDisplayString(textRes.getString("value_required"));
  918.     provinceRequiredPainter.setDisplayString(textRes.getString("value_required"));
  919.     countryRequiredPainter.setDisplayString(textRes.getString("value_required"));
  920.     paymentMethodRequiredPainter.setDisplayString(textRes.getString("value_required"));
  921.     creditCardNoRequiredPainter.setDisplayString(textRes.getString("value_required"));
  922.     orderLineItemSizeItemEditor.setResourceBundle(textRes);
  923.     orderLineItemSizeItemEditor.setCachePickList(false);
  924.     orderLineItemColorItemEditor.setResourceBundle(textRes);
  925.     orderLineItemColorItemEditor.setCachePickList(false);
  926.     exchangeRateDataSet.setColumns(new Column[] {exchangeRateColumn});
  927.     orderDataSet.setColumns(new Column[] {orderNoColumn, orderDateColumn, paymentMethodColumn, creditCardNoColumn, cardExpirationDateColumn});
  928.     productsDataSet.setColumns(new Column[] {unitPriceProductsColumn, descriptionColumn, imageColumn});
  929.     orderLineItemDataSet.setColumns(new Column[] {orderLineItemNoColumn, skuColumn, quantityColumn, sizeColumn, colorColumn, descriptionLookupColumn, unitPriceLineItemColumn, extdPriceColumn, localExtdPriceColumn, subtotalColumn, localSubtotalColumn, shippingColumn, localShippingColumn, taxColumn, localTaxColumn, totalColumn, localTotalColumn, totalQuantityColumn});
  930.     customerDataSet.setColumns(new Column[] {customerNoColumn, lastNameColumn, firstNameColumn, middleNameColumn, address1Column, address2Column, cityColumn, provinceColumn, countryColumn, emailColumn, phoneColumn, faxColumn, passwordColumn, postalCodeColumn});
  931.   }
  932.  
  933.   /**
  934.    * Return the application's single instance of AppDataModule.
  935.    * In order to ensure that the same instance of AppDataModule is
  936.    * used by all parts of the application, AppDataModule follows the
  937.    * 'singleton' object creation pattern.  Clients of the data
  938.    * module must call getDataModule() to get the single instance of
  939.    * AppDataModule.
  940.    *
  941.    * @return instance of the AppDataModule
  942.    */
  943.   static public AppDataModule getDataModule() {
  944.     // Create the instance of AppDataModule the first time
  945.     // getDataModule is called (appDataModule is initially null).
  946.     // If an instance of the data module has already been
  947.     // created, simply return it.
  948.     if (appDataModule == null) {
  949.       appDataModule = new AppDataModule();
  950.     }
  951.     return appDataModule;
  952.   }
  953.  
  954.   /**
  955.    * Specifies a JDBC data source to be used as the application's data provider.
  956.    * To use a JDBC data source instead of TextDataFile as the data
  957.    * source, setJBCDataSource must be called with the appropriate
  958.    * JDBC connection parameters before AppDataModule is instantiated.
  959.    * Note that AppDataModule is instantiated the first time
  960.    * AppDataModule.getDataModule() is called.
  961.    *
  962.    * @param URL Universal Resource Locator for a JDBC database connection
  963.    * @param user user name for a JDBC database connection
  964.    * @param password user name's password for a JDBC database connection
  965.    * @param driver JDBC driver name (e.g. 'interbase.interclient.Driver')
  966.    */
  967.   static public void setJDBCDataSource(String URL, String user, String password, String driver) {
  968.     if (appDataModule == null) {
  969.       jdbcURL = URL;
  970.       jdbcUser = user;
  971.       jdbcPassword = password;
  972.       jdbcDriver = driver;
  973.       useQueryDataSet = true;
  974.     }
  975.   }
  976.  
  977.   /**
  978.    * Returns the customerDataSet data set.
  979.    */
  980.   public borland.sql.dataset.QueryDataSet getCustomerDataSet() {
  981.     return customerDataSet;
  982.   }
  983.  
  984.   /**
  985.    * Returns the customerDataSetView data set.
  986.    */
  987.   public borland.jbcl.dataset.DataSetView getCustomerDataSetView() {
  988.     return customerDataSetView;
  989.   }
  990.  
  991.   /**
  992.    * Returns the exchangeRateDataSet data set.
  993.    */
  994.   public borland.sql.dataset.QueryDataSet getExchangeRateDataSet() {
  995.     return exchangeRateDataSet;
  996.   }
  997.  
  998.   /**
  999.    * Returns the paymentMethodDataSet data set.
  1000.    */
  1001.   public borland.sql.dataset.QueryDataSet getPaymentMethodDataSet() {
  1002.     return paymentMethodDataSet;
  1003.   }
  1004.  
  1005.   /**
  1006.    * Returns the orderDataSet data set.
  1007.    */
  1008.   public borland.sql.dataset.QueryDataSet getOrderDataSet() {
  1009.     return orderDataSet;
  1010.   }
  1011.  
  1012.   /**
  1013.    * Returns the orderLineItemDataSet data set.
  1014.    */
  1015.   public borland.sql.dataset.QueryDataSet getOrderLineItemDataSet() {
  1016.     return orderLineItemDataSet;
  1017.   }
  1018.  
  1019.   /**
  1020.    * Returns the productsDataSet data set.
  1021.    */
  1022.   public borland.sql.dataset.QueryDataSet getProductsDataSet() {
  1023.     return productsDataSet;
  1024.   }
  1025.  
  1026.   /**
  1027.    * Returns the productColorsDataSet data set.
  1028.    */
  1029.   public borland.sql.dataset.QueryDataSet getProductColorsDataSet() {
  1030.     return productColorsDataSet;
  1031.   }
  1032.  
  1033.   /**
  1034.    * Returns the productSizesDataSet data set.
  1035.    */
  1036.   public borland.sql.dataset.QueryDataSet getProductSizesDataSet() {
  1037.     return productSizesDataSet;
  1038.   }
  1039.  
  1040.   /**
  1041.    * Returns the customerNoDataSet data set.
  1042.    */
  1043.   public borland.sql.dataset.QueryDataSet getCustomerNoDataSet() {
  1044.     return customerNoDataSet;
  1045.   }
  1046.  
  1047.   /**
  1048.    * Returns the orderNoDataSet data set.
  1049.    */
  1050.   public borland.sql.dataset.QueryDataSet getOrderNoDataSet() {
  1051.     return orderNoDataSet;
  1052.   }
  1053.  
  1054.   /**
  1055.    * Initializes newly inserted customerDataSet rows.
  1056.    * Assigns each newly inserted customer row a unique customer number and
  1057.    * fills in the country column with the localized country display
  1058.    * name for the current locale.
  1059.    *
  1060.    * @param DataSet DataSet into which a row has been inserted
  1061.    * @exception DataSetException upon invalid use of DataSet
  1062.    */
  1063.   void customerDataSet_inserted(DataSet dataSet) throws DataSetException{
  1064.     // Obtain a new, unique customer number.
  1065.     // queryCustomerNo is used as the row filtering criterion for customerDataSet
  1066.     // to restrict its scope to a single customer row.  When using a TextDataFile, queryCustomerNo is
  1067.     // also used to restrict the scope of orderDataSet to a single customer row.
  1068.  
  1069.     // During a locale change, we save the current edits, cancel them, change the locale
  1070.     // and then restore them.  Thus we don't want to set the customer_no during
  1071.     // a locale change.
  1072.     if (!localeChanging) {
  1073.       saveCustomerNoDataFile = true;
  1074.       queryCustomerNo = getNextInt(customerNoDataSet, "next_customer_no");
  1075.       customerDataSet.setInt("customer_no", queryCustomerNo);
  1076.       customerDataSet.setString("country", LocaleChangeManager.getLocale().getDisplayCountry(LocaleChangeManager.getLocale()));
  1077.     }
  1078.   }
  1079.  
  1080.   /**
  1081.    * Recalculates orderLineItemDataSet's calculated and aggregated value columns.
  1082.    *
  1083.    * @param DataSet DataSet containing changed column 
  1084.    * @param column column which has changed
  1085.    * @param variant new column value (as a Variant)
  1086.    * @exception DataSetException upon invalid use of DataSet
  1087.    */
  1088.   void exchangeRateColumn_changed(DataSet dataSet, Column column, Variant variant) throws DataSetException{
  1089.     orderLineItemDataSet.recalc();
  1090.   }
  1091.  
  1092.   /**
  1093.    * Updates the edit mask of the orderDataSet's credit_card_no column
  1094.    * to the newly selected credit card's digit pattern.
  1095.    *
  1096.    * @param DataSet DataSet containing changed column 
  1097.    * @param column column which has changed
  1098.    * @param variant new column value (as a Variant)
  1099.    * @exception DataSetException upon invalid use of DataSet
  1100.    */
  1101.   void paymentMethodColumn_changed(DataSet dataSet, Column column, Variant variant) throws DataSetException{
  1102.     // locate the credit card no pattern
  1103.     DataRow locateRow = new DataRow(paymentMethodDataSet, new String [] { "credit_card_name" });
  1104.     locateRow.setString("credit_card_name", orderDataSet.getString("payment_method"));
  1105.     paymentMethodDataSet.locate(locateRow, Locate.FIRST);
  1106.     creditCardNoItemEditor.setEditMask(paymentMethodDataSet.getString("digit_pattern"), Variant.STRING, LocaleChangeManager.getLocale());
  1107.   }
  1108.  
  1109.   /**
  1110.    * Initializes newly inserted orderDataSet rows.
  1111.    * Assigns each newly inserted order row a unique order number.
  1112.    *
  1113.    * @param DataSet DataSet into which a row has been inserted
  1114.    * @exception DataSetException upon invalid use of DataSet
  1115.    */
  1116.   void orderDataSet_inserted(DataSet dataSet) throws DataSetException{
  1117.     // During a locale change, we save the current edits, cancel them, change the locale
  1118.     // and then restore them.  Thus we don't want to set the order_no during
  1119.     // a locale change.
  1120.     if (!localeChanging) {
  1121.       saveOrderNoDataFile = true;
  1122.       dataSet.setInt("order_no", getNextInt(orderNoDataSet, "next_order_no"));
  1123.     }
  1124.   }
  1125.  
  1126.   /**
  1127.    * Calculates the extended and localized extended prices of posted
  1128.    * orderLineItemDataSet rows.  Also sets the resource bundle lookup
  1129.    * key for localized orderLineItemDataSet descriptions
  1130.    *
  1131.    * @param readRow row of base values for calculation
  1132.    * @param dataRow row for newly calculated row values
  1133.    * @param isPosted true if readRow is a posted row
  1134.    * @exception DataSetException upon invalid use of DataSet
  1135.    */
  1136.   void orderLineItemDataSet_calcFields(ReadRow readRow, DataRow dataRow, boolean isPosted) throws DataSetException{
  1137.     double extdPrice = readRow.getInt("quantity") * readRow.getDouble("unit_price");
  1138.     dataRow.setDouble("extd_price", extdPrice);
  1139.     dataRow.setDouble("local_extd_price", extdPrice * exchangeRateDataSet.getDouble("exchange_rate"));
  1140.     // The item painter for the description column will lookup the
  1141.     // description for the sku in a resource bundle and display the
  1142.     // localized description
  1143.     if (readRow.getInt("sku") != 0) {
  1144.       // we'll get a value of 0 when a calcFields event occurs due to a row insert.
  1145.       // since there's nothing to display in this case, don't set the value.  Setting
  1146.       // a lookup key value of 0 will cause a missing resource exception, since '0'
  1147.       // is not a valid sku.
  1148.       dataRow.setString("description", "" + readRow.getInt("sku"));
  1149.     }
  1150.   }
  1151.  
  1152.   /**
  1153.    * Recalculates US and localized currency subtotal, shipping, tax,
  1154.    * and total values for the current order when a row is added to
  1155.    * orderLineItemDataSet.
  1156.    *
  1157.    * @param readRow row of base values for calculation
  1158.    * @param readWriteRow row for newly calculated values
  1159.    * @exception DataSetException upon invalid use of DataSet
  1160.    */
  1161.   void orderLineItemDataSet_calcAggAdd(ReadRow readRow, ReadWriteRow readWriteRow) throws DataSetException{
  1162.     double subtotal = readRow.getDouble("subtotal");
  1163.  
  1164.     // Calculate shipping based on number of items
  1165.     double shipping = readRow.getInt("total_quantity") * 4.95;
  1166.     readWriteRow.setDouble("shipping", shipping);
  1167.  
  1168.     // Calculate 8.5% sales tax based on sum of subtotal and shipping
  1169.     double tax = .085 * (subtotal + shipping);
  1170.     readWriteRow.setDouble("tax", tax);
  1171.  
  1172.     double total = subtotal + shipping + tax;
  1173.     readWriteRow.setDouble("total", total);
  1174.  
  1175.     // Calculate local subtotal, shipping, tax, and total based on exchange rate
  1176.     double exchangeRate = exchangeRateDataSet.getDouble("exchange_rate");
  1177.     readWriteRow.setDouble("local_subtotal", subtotal * exchangeRate);
  1178.     readWriteRow.setDouble("local_shipping", shipping * exchangeRate);
  1179.     readWriteRow.setDouble("local_tax", tax * exchangeRate);
  1180.     readWriteRow.setDouble("local_total", total * exchangeRate);
  1181.   }
  1182.  
  1183.   /**
  1184.    * Recalculates US and localized currency subtotal, shipping, tax,
  1185.    * and total values for the current order when a row is removed from
  1186.    * orderLineItemDataSet.
  1187.    *
  1188.    * @param readRow row of base values for calculation
  1189.    * @param readWriteRow row for newly calculated values
  1190.    * @exception DataSetException upon invalid use of DataSet
  1191.    */
  1192.   void orderLineItemDataSet_calcAggDelete(ReadRow readRow, ReadWriteRow readWriteRow) throws DataSetException{
  1193.     // Delegate recalculation of values to orderLineItemDataSet_calcAggAdd()
  1194.     orderLineItemDataSet_calcAggAdd(readRow, readWriteRow);
  1195.   }
  1196.  
  1197.   /**
  1198.    * Refilters rows of productsDataSet according to the current
  1199.    * productFilteringCategory.
  1200.    * productsDataSet_filterRow() is called once for each row
  1201.    * in productsDataSet when productsDataSet.open() or
  1202.    * productsDataSet.refilter() is invoked.  The value of the
  1203.    * productFilteringCategory variable is used to determine which rows
  1204.    * should be filtered into (rowFilterResponse.add()) or filtered out
  1205.    * of (rowFilterResponse.ignore()) the DataSet.  By design, product
  1206.    * categories are assigned integer values.  When the user selects a
  1207.    * new product filtering category, ProductFrame calls the data
  1208.    * module's filterProducts() method, passing it a value
  1209.    * corresponding to the desired filtering category.
  1210.    * filterProducts() assigns the new filtering category to the
  1211.    * productFilteringCategory variable and invokes
  1212.    * productsDataSet.refilter(), causing productsDataSet to be
  1213.    * refiltered adding only the desired rows.  AppDataModule's public
  1214.    * constant NO_PRODUCT_FILTER can be passed to filterProducts() to
  1215.    * filter in all rows.  
  1216.    *
  1217.    * @param readRow row to be filtered
  1218.    * @param rowFilterResponse indicates whether row should be filtered into or out of DataSet
  1219.    * @exception DataSetException upon invalid use of DataSet
  1220.    */
  1221.   void productsDataSet_filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  1222.     if ((productFilteringCategory == NO_PRODUCT_FILTER) ||
  1223.         (readRow.getInt("category") == productFilteringCategory)) {
  1224.       // add row to filtered DataSet
  1225.       rowFilterResponse.add();
  1226.     } else {
  1227.       // do not add row to filtered DataSet
  1228.       rowFilterResponse.ignore();
  1229.     }
  1230.   }
  1231.  
  1232.   /**
  1233.    * Sets the (single) customerDataSet filtered row to be the current
  1234.    * customerDataSetView row if the specified password is valid.
  1235.    * Also removes the unposted, new customer row from customerDataSet
  1236.    * if necessary.  Called by CustomerLookupDialog.java when user
  1237.    * presses 'OK' button to select a customer row.
  1238.    *
  1239.    * @return true if customer password is valid
  1240.    */
  1241.   public boolean isValidCustomerDataViewPassword(String password) {
  1242.     try {
  1243.       String mangledPassword = customerDataSetView.getString("mangled_password");
  1244.       if (mangledPassword.equals(PasswordMangler.manglePassword(password))) {
  1245.         // When a new order is initialized, a row is always inserted into customerDataSet
  1246.         // with a new unique customer_no value (see customerDataSet_inserted()).
  1247.         // If instead of entering a new customer, the user finds an existing customer,
  1248.         // then we first have to remove (cancel) the new customer row we added.
  1249.         customerDataSet.cancel();
  1250.         queryCustomerNo = customerDataSetView.getInt("customer_no");
  1251.         customerDataSet.refilter();
  1252.         return true;
  1253.       }
  1254.     } catch (DataSetException e) {
  1255.       DataSetException.handleException(customerDataSet, null, e, true);
  1256.     }
  1257.     return false;
  1258.   }
  1259.  
  1260.   // called by SoldToPanel.java after an existing customer has been retrieved,
  1261.   // in order to copy the customer's no into the pending order.
  1262.   public void syncCustomerNoWithCurrentOrder() {
  1263.     try {
  1264.       orderDataSet.setInt("customer_no", queryCustomerNo);
  1265.     } catch (DataSetException e) {
  1266.       DataSetException.handleException(orderDataSet, null, e, true);
  1267.     }
  1268.   }
  1269.  
  1270.   /**
  1271.    * Removes the current row from orderLineItemDataSet.
  1272.    * Called by OrderFrame.java when a user clicks the 'Remove Item'
  1273.    * button.
  1274.    */
  1275.   public void removeCurrentLineItem() {
  1276.     try {
  1277.       if (orderLineItemDataSet.getRowCount() > 0) {
  1278.         // In order to prevent users from interactively deleting rows
  1279.         // using [Ctrl][Del], we initially set setEnableDelete(false).
  1280.         // So in order to delete an existing orderLineItem row, we need to set
  1281.         // temporarily do setEnableDelete(true) so we can delete the row.
  1282.         orderLineItemDataSet.setEnableDelete(true);
  1283.         orderLineItemDataSet.deleteRow();
  1284.         orderLineItemDataSet.setEnableDelete(false);
  1285.       }
  1286.     } catch (DataSetException e) {
  1287.       DataSetException.handleException(orderLineItemDataSet, null, e, true);
  1288.     }
  1289.   }
  1290.  
  1291.   /**
  1292.    * Cancels the current order.
  1293.    * Called by OrderFrame.java when a user clicks the 'Cancel Order'
  1294.    * button.
  1295.    */
  1296.   public void cancelOrder() {
  1297.     StorageDataSet dataSet = null;
  1298.     if (enteringOrder) {
  1299.       try {
  1300.         // If we're using a QueryDataSet, then we can simply empty the
  1301.         // orderDataSet and orderLineItemDataSet data sets.
  1302.         if (useQueryDataSet) {
  1303.           (dataSet = orderLineItemDataSet).empty();
  1304.           // Must cancel row currently being edited before doing empty()
  1305.           (dataSet = orderDataSet).cancel();
  1306.           orderDataSet.empty();
  1307.         } else {
  1308.           // When using a TextDataFile data source, we've already loaded
  1309.           // all the orderDataSet and orderLineItemDataSet data, so we
  1310.           // have to remove the current rows we're editing in
  1311.           // orderDataSet and orderLineItemDataSet.  Delete already
  1312.           // posted line items for the current order.
  1313.           // In order to prevent users from interactively deleting rows
  1314.           // using {Ctrl-Del}, we set setEnableDelete(false).
  1315.           // So in order to delete an existing orderLineItem row, we need 
  1316.           // to temporarily set setEnableDelete(true).
  1317.           (dataSet = orderLineItemDataSet).first();
  1318.           orderLineItemDataSet.setEnableDelete(true);
  1319.           while (orderLineItemDataSet.getRowCount() > 0) {
  1320.             orderLineItemDataSet.deleteRow();
  1321.           }
  1322.           orderLineItemDataSet.setEnableDelete(false);
  1323.           (dataSet = orderDataSet).cancel();
  1324.         }
  1325.         // When using either a JDBC database or TextDataFile data source,
  1326.         // we always load in all rows of the customerDataSet, so for the
  1327.         // customerDataSet, we have to cancel the row we were currently
  1328.         // editing.  cancel() on a newly inserted row will remove the
  1329.         // row.  cancel() on a modified, existing row will undo changes
  1330.         // on the row.
  1331.         (dataSet = customerDataSet).cancel();
  1332.         // Reset the enteringOrder value to indicate we are no longer
  1333.         // entering a new order.
  1334.         enteringOrder = false;
  1335.       } catch (DataSetException e) {
  1336.         DataSetException.handleException(dataSet, null, e, true);
  1337.       }
  1338.     }
  1339.   }
  1340.  
  1341.   /**
  1342.    * Saves the current order.
  1343.    * Called by OrderFrame.java when a user clicks on the 'Save Order'
  1344.    * button.  When using a JDBC data source, the order is immediately
  1345.    * resolved back to the database.  When using a TextDataFile data
  1346.    * source, however, changes are not resolved back to the
  1347.    * TextDataFile until resolveData() is called on application exit.
  1348.    *
  1349.    * @param password (non-mangled) password of customer submitting
  1350.    * order
  1351.    * @return false if posting any of the order rows fails (most likely due
  1352.    * to a validation error).
  1353.    */
  1354.   public boolean saveOrder(String password) {
  1355.     DataSet dataSet = null;
  1356.     try {
  1357.       // Copy summary data to master order row and post it
  1358.  
  1359.       // allow us to insert and update the rows
  1360.       customerDataSet.setEnableInsert(true);
  1361.       orderDataSet.setEnableInsert(true);
  1362.       orderLineItemDataSet.setEnableInsert(true);
  1363.  
  1364.       dataSet = orderDataSet;
  1365.       ReadRow.copyTo(new String [] { "subtotal", "tax", "shipping", "total" },
  1366.                      orderLineItemDataSet,
  1367.                      new String [] { "subtotal", "tax", "shipping_charge", "total" },
  1368.                      orderDataSet);
  1369.  
  1370.       orderDataSet.post();
  1371.  
  1372.       // If we added a new customer row or modified an existing one, post it
  1373.       if (isPasswordNeededToSaveOrder()) {
  1374.         customerDataSet.setString("mangled_password", PasswordMangler.manglePassword(password));
  1375.       }
  1376.       (dataSet = customerDataSet).post();
  1377.  
  1378.       // When using a query data set provider, after posting the newly
  1379.       // added order to its corresponding DataSets, we resolve it back
  1380.       // to the JDBC data source.  Note that the default query
  1381.       // resolver is smart enough to resolve only the necessary changes 
  1382.       // to the database.
  1383.       if (useQueryDataSet) {
  1384.         database.saveChanges(new DataSet [] { customerDataSet, orderDataSet, orderLineItemDataSet });
  1385.       }
  1386.       // Reset the enteringOrder value to indicate we are no longer
  1387.       // entering a new order.
  1388.       enteringOrder = false;
  1389.       customerDataSet.setEnableInsert(false);
  1390.       orderDataSet.setEnableInsert(false);
  1391.       orderLineItemDataSet.setEnableInsert(false);
  1392.       return true;
  1393.     } catch (DataSetException e) {
  1394.       DataSetException.handleException(dataSet, null, e, true);
  1395.     }
  1396.     return false;
  1397.   }
  1398.  
  1399.   /**
  1400.    * Returns whether or not a password has already been given for the
  1401.    * current customerDataSet row.  Called by OrderFrame.java to
  1402.    * determine whether or not to prompt the user for a password when
  1403.    * saving an order.  Also called by AppDataModule.saveOrder() to check if a new
  1404.    * password needs to be saved with the current order.
  1405.    *
  1406.    * @return true if a password is needed 
  1407.    */
  1408.   public boolean isPasswordNeededToSaveOrder() {
  1409.     try {
  1410.       return customerDataSet.getString("mangled_password").length() == 0;
  1411.     } catch (DataSetException e) {
  1412.       DataSetException.handleException(customerDataSet, null, e, true);
  1413.     }
  1414.     return false;
  1415.   }
  1416.  
  1417.   /**
  1418.    * Resolves order data back to the appropriate data source.  
  1419.    * When using a JDBC database source, all changes will already have
  1420.    * been posted and resolved, so nothing has to be done.  When using
  1421.    * a TextDataFile, however, changes made to orderDataSet,
  1422.    * orderLineItemDataSet, and customerDataSet need to be saved back
  1423.    * to disk.  Called by WelcomeFrame.java when a user exits the
  1424.    * application.
  1425.    */
  1426.   public void resolveData() {
  1427.     DataSet dataSet = null;
  1428.     try {
  1429.       if (useQueryDataSet) {
  1430.         // No changes need to be saved because orders are posted on saveOrder()
  1431.         database.closeConnection();
  1432.       } else {
  1433.         // If enteringOrder is true at this point, then the user
  1434.         // exited without canceling or saving an order.  In this case,
  1435.         // we remove any posted detail rows in orderLineItemDataSet
  1436.         // and cancel changes in customerDataSet and orderDataSet.
  1437.         // Note that we have to remove the detail rows first, because
  1438.         // if we cancelled the master first, the details would no
  1439.         // longer have a master row, and we wouldn't be able to access
  1440.         // them using orderLineItemDataSet.
  1441.         if (enteringOrder) {
  1442.           (dataSet = orderLineItemDataSet).first();
  1443.           orderLineItemDataSet.setEnableDelete(true);
  1444.           // Delete already posted line items for the current order
  1445.           while (orderLineItemDataSet.getRowCount() > 0) {
  1446.             orderLineItemDataSet.deleteRow();
  1447.           }
  1448.           orderLineItemDataSet.setEnableDelete(false);
  1449.         }
  1450.         orderLineItemDataSet.close();
  1451.  
  1452.         if (enteringOrder) {
  1453.           // Cancel modified or newly inserted customerDataSet row
  1454.           (dataSet = customerDataSet).cancel();
  1455.         }
  1456.         customerDataSet.close();
  1457.         // Remove filter restrictions before saving.
  1458.         // TextDataFile.save() will only save rows which have been filtered
  1459.         // into the DataSet, thus in order to save back all rows we need to 
  1460.         // remove filter restrictions before saving.
  1461.         customerDataSet.removeRowFilterListener(customerDataSet.getRowFilterListener());
  1462.  
  1463.         if (enteringOrder) {
  1464.           // Cancel newly inserted orderDataSet row
  1465.           (dataSet = orderDataSet).cancel();
  1466.         }
  1467.         // Remove filter restrictions before saving.
  1468.         // TextDataFile.save() will only saves rows which have been
  1469.         // filtered into the DataSet, thus in order to save back all
  1470.         // rows we need to remove filter restrictions before saving.
  1471.         orderDataSet.close();
  1472.         orderDataSet.removeRowFilterListener(orderDataSet.getRowFilterListener());
  1473.  
  1474.         // Resolve DataSet changes back to text data file sources
  1475.         customerDataFile.save(dataSet = customerDataSet);
  1476.         orderDataFile.save(dataSet = orderDataSet);
  1477.         orderLineItemDataFile.save(dataSet = orderLineItemDataSet);
  1478.         if (saveCustomerNoDataFile) {
  1479.           customerNoDataFile.save(dataSet = customerNoDataSet);
  1480.         }
  1481.         if (saveOrderNoDataFile) {
  1482.           orderNoDataFile.save(dataSet = orderNoDataSet);
  1483.         }
  1484.       }
  1485.     } catch (DataSetException e) {
  1486.       DataSetException.handleException(dataSet, null, e, true);
  1487.     } catch (Exception e) {
  1488.       borland.jbcl.util.Diagnostic.printStackTrace(e);
  1489.     }
  1490.   }
  1491.  
  1492.   /**
  1493.    * Initializes data entry rows for a new order.  Called by
  1494.    * addProductToOrderLineItem() when a product is inserted into an
  1495.    * order.  Checks whether the order has already been initialized,
  1496.    * and if not, inserts new rows in orderDataSet and customerDataSet.
  1497.    */
  1498.   public void initializeOrder() {
  1499.     DataSet dataSet = null;
  1500.     // enteringOrder tells us whether or not we have already
  1501.     // initialized the order.  Only initialize the order
  1502.     // if we haven't already done so.
  1503.     if (!enteringOrder) {
  1504.       try {
  1505.         if (useQueryDataSet) {
  1506.           // If we're using a JDBC database source, execute a query
  1507.           // which always returns an empty result.  This has the side
  1508.           // effect of loading database metadata into the DataSet so
  1509.           // that we can simply add new rows to orderDataSet and
  1510.           // orderLineItemDataSet and then post changes back with
  1511.           // database.saveChanges().  For customerDataSet, since we
  1512.           // always provide all customerDataSet rows, we use a
  1513.           // RowFilterListener to simply restrict the user to
  1514.           // navigating a single customer row.
  1515.  
  1516.           // Get the query parameters for the orderDataSet query, and
  1517.           // set them to a condition which guarantees an empty result.
  1518.           ReadWriteRow parameterRow = orderDataSet.getParameterRow();
  1519.           parameterRow.setInt("customer_no", INVALID_CUSTOMER);
  1520.           dataSet = orderDataSet;
  1521.  
  1522.           // Execute a query on orderDataSet which should return no
  1523.           // rows.  Because there's a MasterLinkDescriptor connecting
  1524.           // orderLineItemDataSet to orderDataSet that specifies that  
  1525.           // linked detail rows should be fetched as needed, executing
  1526.           // the query on orderDataSet also executes the query on
  1527.           // orderLineItemDataSet.
  1528.           orderDataSet.executeQuery();
  1529.  
  1530.           // Open the DataSets for subsequent DataSet operations
  1531.           orderDataSet.open();
  1532.           orderLineItemDataSet.open();
  1533.         }
  1534.         // 'inserted' event handlers on orderDataSet and
  1535.         // customerDataSet put the proper values into the newly
  1536.         // inserted rows.
  1537.  
  1538.         orderDataSet.setEnableInsert(true);
  1539.         (dataSet = orderDataSet).insertRow(false);
  1540.         orderDataSet.setEnableInsert(false);
  1541.         customerDataSet.setEnableInsert(true);
  1542.         (dataSet = customerDataSet).insertRow(false);
  1543.         customerDataSet.setEnableInsert(false);
  1544.         (dataSet = orderDataSet).setInt("customer_no", customerDataSet.getInt("customer_no"));
  1545.         
  1546.         // Set enteringOrder to true so that the next time
  1547.         // initializeOrder() is called by addProductToOrderLineItem(),
  1548.         // we'll know to not reinitialize the order again.
  1549.         enteringOrder = true;
  1550.       } catch (Exception e) {
  1551.         DataSetException.handleException(dataSet, null, e, true);
  1552.       }
  1553.     }
  1554.   }
  1555.  
  1556.   /**
  1557.    * Inserts information from the current row of productsDataSet into
  1558.    * orderLineItemDataSet.  Called by ProductFrame.java when a user
  1559.    * presses the "Add product to Order" button.  When inserting the
  1560.    * new order row into the orderLineItemDataSet, we check to see if
  1561.    * an identical item already exists (same sku and detail info), and
  1562.    * if so, simply increment its quantity in the order.
  1563.    */
  1564.   public void addProductToOrderLineItem() {
  1565.     try {
  1566.       // Insert and initialize new rows in orderDataSet,
  1567.       // customerDataSet, and orderLineItemDataSet if not already
  1568.       // done.
  1569.       initializeOrder();
  1570.  
  1571.       // Build a scoped DataRow (on the sku and details columns) for
  1572.       // use in locating a duplicate item already in the order.
  1573.       DataRow locateRow = new DataRow(orderLineItemDataSet, new String [] { "sku", "sizes", "colors" });
  1574.       locateRow.setInt("sku", productsDataSet.getInt("sku"));
  1575.       String color = getCurrentProductDefaultColor();
  1576.       locateRow.setString("colors", color);
  1577.       String size = getCurrentProductDefaultSize();
  1578.       locateRow.setString("sizes", size);
  1579.  
  1580.       // See if an identical order line item (same sku and details
  1581.       // column values) already exists.
  1582.       if ((orderLineItemDataSet.getRowCount() > 0) && (orderLineItemDataSet.locate(locateRow, Locate.FIRST))) {
  1583.         // If we found the same item, just increase its quantity value
  1584.         orderLineItemDataSet.setInt("quantity", orderLineItemDataSet.getInt("quantity")+1);
  1585.       } else {
  1586.         // Otherwise, insert a row for the new item.
  1587.  
  1588.         orderLineItemDataSet.setEnableInsert(true);
  1589.         orderLineItemDataSet.insertRow(false);
  1590.         orderLineItemDataSet.setInt("sku", productsDataSet.getInt("sku"));
  1591.         orderLineItemDataSet.setInt("quantity", 1);
  1592.         orderLineItemDataSet.setDouble("unit_price", productsDataSet.getDouble("unit_price"));
  1593.         orderLineItemDataSet.setString("sizes", size);
  1594.         orderLineItemDataSet.setString("colors", color);
  1595.       }
  1596.       // Post new change to update calculated aggregate values
  1597.       orderLineItemDataSet.post();
  1598.       orderLineItemDataSet.setEnableInsert(false);
  1599.     } catch (DataSetException e) {
  1600.       DataSetException.handleException(orderLineItemDataSet, null, e, true);
  1601.     }
  1602.   }
  1603.  
  1604.   /**
  1605.    * Record new product filtering category and force refiltering to
  1606.    * occur.  Called by ProductFrame.java when a user changes the
  1607.    * current product filtering category.
  1608.    *
  1609.    * @param productFilteringCategory NO_PRODUCT_FILTER for all
  1610.    * products, 1 for software products only, 2 for deskware products
  1611.    * only, 3 for bodyware products only.  
  1612.    */
  1613.   public void filterProducts(int productFilteringCategory) {
  1614.     try {
  1615.       this.productFilteringCategory = productFilteringCategory;
  1616.       // Invoke the productsDataSet's RowFilterListener to filter rows
  1617.       // based on new filter criterion
  1618.       productsDataSet.refilter();
  1619.     } catch (Exception e) {
  1620.       DataSetException.handleException(productsDataSet, null, e, true);
  1621.     }
  1622.   }
  1623.  
  1624.   /**
  1625.    * Returns default color for the current row of the productsDataSet.
  1626.    * Called by addProductToOrderLineItem() when inserting a new row.
  1627.    * 
  1628.    * @return non-localized string containing default product color 
  1629.    * or an empty string if the product has no color.
  1630.    */
  1631.   String getCurrentProductDefaultColor() {
  1632.     String color = "";
  1633.     try {
  1634.       int sku = productsDataSet.getInt("sku");
  1635.  
  1636.       // Create a DataRow scoped on the sku column for doing a locate
  1637.       // within productColorsDataSet.
  1638.       DataSetView colorsView = productColorsDataSet.cloneDataSetView();
  1639.       DataRow locateRow = new DataRow(colorsView, new String [] { "sku" });
  1640.       locateRow.setInt("sku", sku);
  1641.       // Locate the first color choice for the sku
  1642.       if (colorsView.locate(locateRow, Locate.FIRST)) {
  1643.         color = colorsView.getString("available_colors");
  1644.       }
  1645.  
  1646.     } catch (Exception e) {
  1647.       DataSetException.handleException(productColorsDataSet, null, e, true);
  1648.     }
  1649.     return color;
  1650.   }
  1651.  
  1652.   /**
  1653.    * Returns default size for the current row of the productsDataSet.
  1654.    * Called by addProductToOrderLineItem() when inserting a new row.
  1655.    * 
  1656.    * @return non-localized string containing default product size
  1657.    * or an empty string if the product has no size.
  1658.    */
  1659.   String getCurrentProductDefaultSize() {
  1660.     String size = "";
  1661.     try {
  1662.       int sku = productsDataSet.getInt("sku");
  1663.  
  1664.       // Create a DataRow scoped on the sku column for doing a locate
  1665.       // within productSizesDataSet.
  1666.       DataSetView sizesView = productSizesDataSet.cloneDataSetView();
  1667.       DataRow locateRow = new DataRow(sizesView, new String [] { "sku" });
  1668.       locateRow.setInt("sku", sku);
  1669.       // Locate the first size choice for the sku
  1670.       if (sizesView.locate(locateRow, Locate.FIRST)) {
  1671.         size = sizesView.getString("available_sizes");
  1672.       }
  1673.  
  1674.     } catch (Exception e) {
  1675.       DataSetException.handleException(productSizesDataSet, null, e, true);
  1676.     }
  1677.     return size;
  1678.   }
  1679.  
  1680.   /**
  1681.    * Configures data sets for browsing previous orders of the customer
  1682.    * indicated by the customerDataSet's current row.
  1683.    * Called by WelcomeFrame.java when user clicks 'View Previous
  1684.    * Orders' button, and also OrderFrame.java when user closes frame
  1685.    * after having viewed orders.
  1686.    * 
  1687.    * @param browseCustomerOrders if true, prepares data sets for
  1688.    * browsing a customer's previous orders.  
  1689.    */
  1690.   public void browseCustomerOrders(boolean browseCustomerOrders) {
  1691.     StorageDataSet dataSet = null;
  1692.     try {
  1693.       if (browseCustomerOrders) {
  1694.         // queryCustomerNo (set by CustomerLookupDialog.java's call to isValidCustomerDataViewPassword())
  1695.         // should contain contain the correct customer no 
  1696.         if (useQueryDataSet) {
  1697.           // If using a JDBC database, execute a query which selects
  1698.           // rows from orderDataSet for the selected customer.
  1699.           // Because orderLineItemDataSet's MasterLinkDescriptor
  1700.           // specifies linked detail rows should be fetched as needed,
  1701.           // executing the query on orderDataSet automatically fetches
  1702.           // the corresponding orderLineItemDataSet linked detail rows.
  1703.           ReadWriteRow parameterRow = orderDataSet.getParameterRow();
  1704.           parameterRow.setInt("customer_no", queryCustomerNo);
  1705.           dataSet = orderDataSet;
  1706.           orderDataSet.executeQuery();
  1707.         } else {
  1708.           // If using a TextDataFile source, force refiltering of
  1709.           // orderDataSet's rows for the selected customer.
  1710.           (dataSet = orderDataSet).refilter();
  1711.         }
  1712.         // Force updating of calculated aggregate values
  1713.         orderLineItemDataSet.recalc();
  1714.       } else {
  1715.         queryCustomerNo = INVALID_CUSTOMER;
  1716.         if (useQueryDataSet) {
  1717.           // If we're no longer browsing a customer's previous orders,
  1718.           // we can simply empty the rows from the DataSet.  Note that
  1719.           // empty() discards query resolver information so that when the
  1720.           // data set is resolved (when posting a new order), rows
  1721.           // emptied here will not be deleted from the server.
  1722.           (dataSet = orderDataSet).empty();
  1723.           (dataSet = orderLineItemDataSet).empty();
  1724.         } else {
  1725.           // If we're using a TextDataFile data source, refilter orderDataSet
  1726.           // for no order rows.
  1727.           (dataSet = orderDataSet).refilter();
  1728.         }
  1729.       }
  1730.     } catch (Exception e) {
  1731.       DataSetException.handleException(dataSet, null, e, true);
  1732.     }
  1733.   }
  1734.  
  1735.   /**
  1736.    * Restricts navigation of orderDataSet to rows for the current customer (stored in queryCustomerNo).
  1737.    *
  1738.    * @param readRow row to be filtered
  1739.    * @param rowFilterResponse indicates whether row should be filtered into or out of DataSet
  1740.    * @exception DataSetException upon invalid use of DataSet
  1741.    */
  1742.   void orderDataSet_filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  1743.     if (readRow.getInt("customer_no") == queryCustomerNo) {
  1744.       // Add row to filtered DataSet
  1745.       rowFilterResponse.add();
  1746.     } else {
  1747.       // Do not add row to filtered DataSet
  1748.       rowFilterResponse.ignore();
  1749.     }
  1750.   }
  1751.  
  1752.   /**
  1753.    * Sets the current row of the exchangeRateDataSet to the current locale's country.
  1754.    * If a country can't be found, the current row is set to the row for "US".
  1755.    * Localized calculations are performed based upon the conversion rate taken from the
  1756.    * current row of exchangeRateDataSet.
  1757.    */
  1758.   private void readExchangeRate() {
  1759.     try {
  1760.       // Build a scoped DataRow (on the country_code column) for
  1761.       // use in locating a country code.
  1762.       DataRow locateRow = new DataRow(exchangeRateDataSet, new String [] { "country_code" });
  1763.  
  1764.       locateRow.setString("country_code", LocaleChangeManager.getLocale().getCountry());
  1765.       // If the country exists in exchangeRateDataSet, the following locate() should
  1766.       // position the current row of exchangeRateDataSet to that row.
  1767.       if (!exchangeRateDataSet.locate(locateRow, Locate.FIRST)) {
  1768.         // If we couldn't find the country, set the rate to the US rate.
  1769.         locateRow.setString("country_code", "US");
  1770.         exchangeRateDataSet.locate(locateRow, Locate.FIRST);
  1771.       }
  1772.     } catch (Exception e) {
  1773.       DataSetException.handleException(exchangeRateDataSet, null, e, true);
  1774.     }
  1775.   }
  1776.  
  1777.   /**
  1778.    * Increments an integer value the specified column of a DataSet.
  1779.    * Called by the DataSet 'inserted' event handlers for
  1780.    * customerDataSet and orderDataSet to get unique customer and order
  1781.    * numbers, respectively.  When using a JDBC database, assumes that
  1782.    * a query has already been defined for the DataSet which provides
  1783.    * the row to be incremented.  After the value is incremented, it is
  1784.    * immediately posted back to the server.
  1785.    *
  1786.    * @param DataSet name of DataSet containing integer columnName
  1787.    * @param columnName column name of DataSet containing integer value
  1788.    * to be incremented
  1789.    * @return incremented integer value
  1790.    */
  1791.   int getNextInt(QueryDataSet dataset, String columnName) throws DataSetException{
  1792.     if (useQueryDataSet) {
  1793.       dataset.executeQuery();
  1794.     }
  1795.     dataset.open();
  1796.     int nextInt = dataset.getInt(columnName);
  1797.     dataset.setInt(columnName, nextInt + 1);
  1798.     dataset.post();
  1799.     if (useQueryDataSet) {
  1800.       dataset.saveChanges(dataset);
  1801.     }
  1802.     return nextInt;
  1803.   }
  1804.  
  1805.   /**
  1806.    * Updates localized resources for newly selected locale.
  1807.    * Required for implementation of LocaleChangeListener interface.
  1808.    * 
  1809.    * @param e LocaleChangeEvent providing information about new locale 
  1810.    */
  1811.   public void localeChanged(LocaleChangeEvent e) {
  1812.     localeChanging = true;
  1813.     try {
  1814.  
  1815.       // Get resource bundles for new locale
  1816.       textRes = java.util.ResourceBundle.getBundle("borland.samples.intl.application.resources.TextRes", e.getLocale());
  1817.  
  1818.       // Changing to a different locale requires us to close datasets
  1819.       // and reopen them for the new locale.
  1820.  
  1821.       DataRow [] orderLineItemRow = null;
  1822.       int currentOrderItemRow = 0;
  1823.       int orderNo = 0;
  1824.       Timestamp orderDate = null;
  1825.       String paymentMethod = null;
  1826.       String creditCardNo = null;
  1827.       Variant cardExpirationDate = null;
  1828.       int customerNo = 0;
  1829.       String lastName = null;
  1830.       String firstName = null;
  1831.       String middleName = null;
  1832.       String address1 = null;
  1833.       String address2 = null;
  1834.       String city = null;
  1835.       String province = null;
  1836.       String country = null;
  1837.       String eMail = null;
  1838.       String phone = null;
  1839.       String fax = null;
  1840.       String postalCode = null;
  1841.  
  1842.       if (enteringOrder) {
  1843.         // Save the rows of the current order so we can restore them later.
  1844.         // orderLineItemDataSet row storage
  1845.         orderLineItemRow = new DataRow[orderLineItemDataSet.getRowCount()];
  1846.         currentOrderItemRow = orderLineItemDataSet.getRow();
  1847.         for (int rowNo = 0; rowNo < orderLineItemRow.length; rowNo++) {
  1848.           orderLineItemRow[rowNo] = new DataRow(orderLineItemDataSet, new String [] { "sku", "quantity", "sizes", "colors", "unit_price"} );
  1849.           orderLineItemDataSet.getDataRow(rowNo, orderLineItemRow[rowNo]);
  1850.         }
  1851.  
  1852.         // If any of the orderDataSet's columns don't satisfy a validation
  1853.         // constraint, then saving those values in a DataRow created from
  1854.         // orderDataSet will throw a validation exception.  Thus we can't
  1855.         // use a DataRow to save the orderDataSet row data as we did with
  1856.         // orderLineItemRow above.
  1857.         orderNo = orderDataSet.getInt("order_no");
  1858.         orderDate = orderDataSet.getTimestamp("order_date");
  1859.         paymentMethod = orderDataSet.getString("payment_method");
  1860.         creditCardNo = orderDataSet.getString("credit_card_no");
  1861.         cardExpirationDate = new Variant();
  1862.         orderDataSet.getVariant("card_expiration_date", cardExpirationDate);
  1863.  
  1864.       // If any of the customerDataSet's columns don't satisfy a validation
  1865.       // constraint, then saving those values in a DataRow created from
  1866.       // customerDataSet will throw a validation exception.  Thus we can't
  1867.       // use a DataRow to save the customerDataSet row data as we did with
  1868.       // orderLineItemRow above.
  1869.         customerNo = customerDataSet.getInt("customer_no");
  1870.         lastName = customerDataSet.getString("last_name");
  1871.         firstName = customerDataSet.getString("first_name");
  1872.         middleName = customerDataSet.getString("middle_name");
  1873.         address1 = customerDataSet.getString("address1");
  1874.         address2 = customerDataSet.getString("address2");
  1875.         city = customerDataSet.getString("city");
  1876.         province = customerDataSet.getString("province");
  1877.         country = customerDataSet.getString("country");
  1878.         eMail = customerDataSet.getString("e_mail");
  1879.         phone = customerDataSet.getString("phone");
  1880.         fax = customerDataSet.getString("fax");
  1881.         postalCode = customerDataSet.getString("postal_code");
  1882.  
  1883.         // Cancel the order
  1884.         cancelOrder();
  1885.         // When we cancel the order using cancelOrder(), enteringOrder is set
  1886.         // to false.  Since we re-insert the order after the locale change,
  1887.         // we need to reset enteringOrder to be true.  (enteringOrder is the flag
  1888.         // used to determine whether to cancel the current order on exit from
  1889.         // the application.
  1890.         enteringOrder = true;
  1891.       }
  1892.  
  1893.       // Close the datasets so we can set new locale settings
  1894.       orderLineItemDataSet.close();
  1895.       orderDataSet.close();
  1896.       customerDataSet.close();
  1897.  
  1898.       // Set new localized captions
  1899.       lastNameColumn.setCaption(textRes.getString("last_name"));
  1900.       middleNameColumn.setCaption(textRes.getString("middle_name"));
  1901.       firstNameColumn.setCaption(textRes.getString("first_name"));
  1902.       address1Column.setCaption(textRes.getString("address1"));
  1903.       address2Column.setCaption(textRes.getString("address2"));
  1904.       cityColumn.setCaption(textRes.getString("city"));
  1905.       provinceColumn.setCaption(textRes.getString("province"));
  1906.       countryColumn.setCaption(textRes.getString("country"));
  1907.       emailColumn.setCaption(textRes.getString("e_mail"));
  1908.       phoneColumn.setCaption(textRes.getString("phone"));
  1909.       faxColumn.setCaption(textRes.getString("fax"));
  1910.       postalCodeColumn.setCaption(textRes.getString("postal_code"));
  1911.  
  1912.       // Set new localized edit masks
  1913.       postalCodeColumn.setEditMask(textRes.getString("postal_code_editmask"));
  1914.       phoneColumn.setEditMask(textRes.getString("phone_editmask"));
  1915.       faxColumn.setEditMask(textRes.getString("phone_editmask"));
  1916.       provinceColumn.setEditMask(textRes.getString("province_editmask"));
  1917.  
  1918.       // Set new localized captions
  1919.       quantityColumn.setCaption(textRes.getString("quantity"));
  1920.       sizeColumn.setCaption(textRes.getString("size"));
  1921.       colorColumn.setCaption(textRes.getString("color"));
  1922.       descriptionLookupColumn.setCaption(textRes.getString("description"));
  1923.       unitPriceLineItemColumn.setCaption(textRes.getString("unit_price"));
  1924.       extdPriceColumn.setCaption(textRes.getString("extd_price"));
  1925.       localExtdPriceColumn.setCaption(textRes.getString("local_price"));
  1926.       skuColumn.setCaption(textRes.getString("sku"));
  1927.  
  1928.       // Set new localized edit and display masks
  1929.       cardExpirationDateColumn.setEditMask(textRes.getString("month_year_editmask"));
  1930.       orderDateColumn.setDisplayMask(((SimpleDateFormat) SimpleDateFormat.getDateInstance(DateFormat.DEFAULT, e.getLocale())).toPattern());
  1931.       cardExpirationDateColumn.setDisplayMask(textRes.getString("month_year_editmask"));
  1932.  
  1933.       if (LocaleChangeManager.getLocale().equals(Locale.ITALY) ||
  1934.           LocaleChangeManager.getLocale().getCountry().equals("CH")) {
  1935.         localExtdPriceColumn.setDisplayMask(null);
  1936.         localSubtotalColumn.setDisplayMask(null);
  1937.         localShippingColumn.setDisplayMask(null);
  1938.         localTaxColumn.setDisplayMask(null);
  1939.         localTotalColumn.setDisplayMask(null);
  1940.       } else {
  1941.         localExtdPriceColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  1942.         localSubtotalColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  1943.         localShippingColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  1944.         localTaxColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  1945.         localTotalColumn.setDisplayMask(((DecimalFormat) DecimalFormat.getCurrencyInstance(LocaleChangeManager.getLocale())).toPattern());
  1946.       }
  1947.  
  1948.       // Set new localized 'value required' string
  1949.       lastNameRequiredPainter.setDisplayString(textRes.getString("value_required"));
  1950.       firstNameRequiredPainter.setDisplayString(textRes.getString("value_required"));
  1951.       address1RequiredPainter.setDisplayString(textRes.getString("value_required"));
  1952.       cityRequiredPainter.setDisplayString(textRes.getString("value_required"));
  1953.       provinceRequiredPainter.setDisplayString(textRes.getString("value_required"));
  1954.       countryRequiredPainter.setDisplayString(textRes.getString("value_required"));
  1955.       paymentMethodRequiredPainter.setDisplayString(textRes.getString("value_required"));
  1956.       creditCardNoRequiredPainter.setDisplayString(textRes.getString("value_required"));
  1957.  
  1958.       // Set new resource bundle for localized description lookup painter
  1959.       descriptionLookupItemPainter.setResourceBundle(textRes);
  1960.       
  1961.  
  1962.       // Set new resource bundle for order line item size and color picklist item painters and editors
  1963.       orderLineItemSizeItemPainter.setResourceBundle(textRes);
  1964.       orderLineItemColorItemPainter.setResourceBundle(textRes);
  1965.       orderLineItemSizeItemEditor.setResourceBundle(textRes);
  1966.       orderLineItemColorItemEditor.setResourceBundle(textRes);
  1967.  
  1968.       // Reopen datasets
  1969.       orderLineItemDataSet.open();
  1970.       orderDataSet.open();
  1971.       customerDataSet.open();
  1972.  
  1973.       // Restore rows to their state before the locale change.
  1974.       // Insert master before inserting linked detail rows
  1975.  
  1976.       if (enteringOrder) {
  1977.         // Re-insert order row data.  If any of the required columns were blank,
  1978.         // don't set the value, since doing so will cause a validation exception.
  1979.         orderDataSet.setEnableInsert(true);
  1980.         orderDataSet.insertRow(false);
  1981.         orderDataSet.setEnableInsert(false);
  1982.         orderDataSet.setInt("order_no", orderNo);
  1983.         orderDataSet.setTimestamp("order_date", orderDate);
  1984.         if (paymentMethod.length() != 0) {
  1985.           orderDataSet.setString("payment_method", paymentMethod);
  1986.         }
  1987.         if (creditCardNo.length() != 0) {
  1988.           orderDataSet.setString("credit_card_no", creditCardNo);
  1989.         }
  1990.         if (!cardExpirationDate.isNull()) {
  1991.           orderDataSet.setVariant("card_expiration_date", cardExpirationDate);
  1992.         }
  1993.  
  1994.         // Re-insert the order line item data.  Since the DataRow was scoped to
  1995.         // only contain editable columns, and there are no validation checks
  1996.         // on its scoped columns, we can just use updateRow() to restore the data.
  1997.         orderLineItemDataSet.setEnableInsert(true);
  1998.         for (int rowNo = 0; rowNo < orderLineItemRow.length; rowNo++) {
  1999.           orderLineItemDataSet.insertRow(false);
  2000.           orderLineItemDataSet.updateRow(orderLineItemRow[rowNo]);
  2001.           orderLineItemDataSet.post();
  2002.         }
  2003.         if (currentOrderItemRow != -1) {
  2004.           orderLineItemDataSet.goToRow(currentOrderItemRow);
  2005.         }
  2006.         orderLineItemDataSet.setEnableInsert(false);
  2007.  
  2008.       // Re-insert customer row data.  Since we could have been entering
  2009.       // a new row or editing an existing one, first try to see if the row
  2010.       // already exists within the dataset.  If so, then we'll update its
  2011.       // values.  If not, we'll insert a new row for the new customer data.
  2012.         DataRow locateRow = new DataRow(customerDataSet, "customer_no");
  2013.         locateRow.setInt("customer_no", customerNo);
  2014.  
  2015.       // Search for the customer row.  If we find it, we'll be positioned
  2016.       // on the proper row, so all we'll need to do is restore its values.
  2017.       // If we don't find the row, then we need to insert a new row for
  2018.       // this new customer.
  2019.         if (!customerDataSet.locate(locateRow, Locate.FIRST)) {
  2020.           customerDataSet.setEnableInsert(true);
  2021.           customerDataSet.insertRow(false);
  2022.           customerDataSet.setInt("customer_no", customerNo);
  2023.           customerDataSet.setEnableInsert(false);
  2024.         }
  2025.         // If any of the required columns were blank,
  2026.         // don't set the value, since doing so will cause a validation exception.
  2027.         if (lastName.length() != 0) {
  2028.           customerDataSet.setString("last_name", lastName);
  2029.         }
  2030.         if (firstName.length() != 0) {
  2031.           customerDataSet.setString("first_name", firstName);
  2032.         }
  2033.         customerDataSet.setString("middle_name", middleName);
  2034.         if (address1.length() != 0) {
  2035.           customerDataSet.setString("address1", address1);
  2036.         }
  2037.         customerDataSet.setString("address2", address2);
  2038.         if (city.length() != 0) {
  2039.           customerDataSet.setString("city", city);
  2040.         }
  2041.         if (province.length() != 0) {
  2042.           customerDataSet.setString("province", province);
  2043.         }
  2044.         if (country.length() != 0) {
  2045.           customerDataSet.setString("country", country);
  2046.         }
  2047.         customerDataSet.setString("e_mail", eMail);
  2048.         customerDataSet.setString("phone", phone);
  2049.         customerDataSet.setString("fax", fax);
  2050.         customerDataSet.setString("postal_code", postalCode);
  2051.       }
  2052.  
  2053.       // When the locale changes, we need to get localized description data for the new locale.
  2054.       // Note that by using productsDataSetView here instead of productsDataSet, we don't need
  2055.       // to save and restore our current cursor position within the productsDataSet, and the
  2056.       // ProductsFrame will only refresh its currently displayed row (since it's using
  2057.       // productsDataSet as its data set)
  2058.       DataSetView productsDataSetView = new DataSetView();
  2059.       productsDataSetView.setStorageDataSet(productsDataSet);
  2060.       productsDataSetView.open();
  2061.       productsDataSetView.first();
  2062.  
  2063.       // Add localized description data
  2064.       while (productsDataSetView.inBounds()) {
  2065.         int sku = productsDataSetView.getInt("sku");
  2066.         String localizedDescription = textRes.getString("" + sku);
  2067.         productsDataSetView.setString("description", localizedDescription);
  2068.         productsDataSetView.next();
  2069.       }
  2070.       productsDataSetView.post();
  2071.       productsDataSetView.close();
  2072.  
  2073.       // Update exchangeRateDataSet to point to new country's exchange rate
  2074.       readExchangeRate();
  2075.  
  2076.       // Force calc columns to be recalculated based on new exchange rate values
  2077.       orderLineItemDataSet.recalc();
  2078.  
  2079.     } catch (Exception ex) {
  2080.       borland.jbcl.util.Diagnostic.printStackTrace(ex);
  2081.     }
  2082.     localeChanging = false;
  2083.   }
  2084.  
  2085.   /**
  2086.    * Forces calculated aggregates to be updated immediately by posting
  2087.    * a row when its quantity value changes.  Note that aggregated
  2088.    * calculations are only performed on posted rows.  Normal
  2089.    * calculated columns, in constrast, can be updated immediately when
  2090.    * the quantity value is 'put' and do not require the row to be
  2091.    * posted.
  2092.    *
  2093.    * @param DataSet DataSet containing changed column 
  2094.    * @param column column which has changed
  2095.    * @param variant new column value (as a Variant)
  2096.    * @exception DataSetException upon invalid use of DataSet
  2097.    */
  2098.   void quantityColumn_changed(DataSet dataSet, Column column, Variant variant) throws DataSetException{
  2099.     orderLineItemDataSet.post();
  2100.   }
  2101.  
  2102.   /**
  2103.    * Filters all but the current customer number row (stored in
  2104.    * queryCustomerNo) out of customerDataSet.
  2105.    *
  2106.    * @param readRow row to be filtered
  2107.    * @param rowFilterResponse indicates whether row should be filtered into or out of DataSet
  2108.    * @exception DataSetException upon invalid use of DataSet
  2109.    */
  2110.   void customerDataSet_filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  2111.     if (readRow.getInt("customer_no") == queryCustomerNo) {
  2112.       // Add row to filtered DataSet
  2113.       rowFilterResponse.add();
  2114.     } else {
  2115.       // Do not add row to filtered DataSet
  2116.       rowFilterResponse.ignore();
  2117.     }
  2118.   }
  2119.  
  2120.   /**
  2121.    * Filters in only those colors available for the current product.
  2122.    * Called by orderLineItemColorItemEditor when adding picklist values to its Choice.
  2123.    *
  2124.    * @param readRow row to be filtered
  2125.    * @param rowFilterResponse indicates whether row should be filtered into or out of DataSet
  2126.    * @exception DataSetException upon invalid use of DataSet
  2127.    */
  2128.   void orderLineItemColorItemEditor_filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  2129.     if (readRow.getInt("sku") == orderLineItemDataSet.getInt("sku")) {
  2130.       // Add row to filtered DataSet
  2131.       rowFilterResponse.add();
  2132.     } else {
  2133.       // Do not add row to filtered DataSet
  2134.       rowFilterResponse.ignore();
  2135.     }
  2136.   }
  2137.  
  2138.   /**
  2139.    * Filters in only those sizes available for the current product.
  2140.    * Called by orderLineItemSizeItemEditor when adding picklist values to its Choice.
  2141.    *
  2142.    * @param readRow row to be filtered
  2143.    * @param rowFilterResponse indicates whether row should be filtered into or out of DataSet
  2144.    * @exception DataSetException upon invalid use of DataSet
  2145.    */
  2146.   void orderLineItemSizeItemEditor_filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  2147.     if (readRow.getInt("sku") == orderLineItemDataSet.getInt("sku")) {
  2148.       // Add row to filtered DataSet
  2149.       rowFilterResponse.add();
  2150.     } else {
  2151.       // Do not add row to filtered DataSet
  2152.       rowFilterResponse.ignore();
  2153.     }
  2154.   }
  2155.  
  2156. }
  2157.  
  2158. // The following adapter classes were created by the UI Designer to hook
  2159. // up DataSet events to the appropriate methods in AppDataModule.
  2160.  
  2161. class AppDataModule_customerDataSet_editAdapter extends borland.jbcl.dataset.EditAdapter {
  2162.   AppDataModule adaptee;
  2163.  
  2164.   AppDataModule_customerDataSet_editAdapter(AppDataModule adaptee) {
  2165.     this.adaptee = adaptee;
  2166.   }
  2167.  
  2168.   public void inserted(DataSet dataSet) throws DataSetException{
  2169.     adaptee.customerDataSet_inserted(dataSet);
  2170.   }
  2171.  
  2172. }
  2173.  
  2174. class AppDataModule_exchangeRateColumn_columnChangeAdapter extends borland.jbcl.dataset.ColumnChangeAdapter {
  2175.   AppDataModule adaptee;
  2176.  
  2177.   AppDataModule_exchangeRateColumn_columnChangeAdapter(AppDataModule adaptee) {
  2178.     this.adaptee = adaptee;
  2179.   }
  2180.  
  2181.   public void changed(DataSet dataSet, Column column, Variant variant) throws DataSetException{
  2182.     adaptee.exchangeRateColumn_changed(dataSet, column, variant);
  2183.   }
  2184. }
  2185.  
  2186. class AppDataModule_paymentMethodColumn_columnChangeAdapter extends borland.jbcl.dataset.ColumnChangeAdapter {
  2187.   AppDataModule adaptee;
  2188.  
  2189.   AppDataModule_paymentMethodColumn_columnChangeAdapter(AppDataModule adaptee) {
  2190.     this.adaptee = adaptee;
  2191.   }
  2192.  
  2193.   public void changed(DataSet dataSet, Column column, Variant variant) throws DataSetException{
  2194.     adaptee.paymentMethodColumn_changed(dataSet, column, variant);
  2195.   }
  2196. }
  2197.  
  2198. class AppDataModule_orderDataSet_editAdapter extends borland.jbcl.dataset.EditAdapter {
  2199.   AppDataModule adaptee;
  2200.  
  2201.   AppDataModule_orderDataSet_editAdapter(AppDataModule adaptee) {
  2202.     this.adaptee = adaptee;
  2203.   }
  2204.  
  2205.   public void inserted(DataSet dataSet) throws DataSetException{
  2206.     adaptee.orderDataSet_inserted(dataSet);
  2207.   }
  2208.  
  2209. }
  2210.  
  2211. class AppDataModule_orderLineItemDataSet_calcFieldsAdapter implements borland.jbcl.dataset.CalcFieldsListener {
  2212.   AppDataModule adaptee;
  2213.  
  2214.   AppDataModule_orderLineItemDataSet_calcFieldsAdapter(AppDataModule adaptee) {
  2215.     this.adaptee = adaptee;
  2216.   }
  2217.  
  2218.   public void calcFields(ReadRow readRow, DataRow dataRow, boolean boolean1) throws DataSetException{
  2219.     adaptee.orderLineItemDataSet_calcFields(readRow, dataRow, boolean1);
  2220.   }
  2221. }
  2222.  
  2223. class AppDataModule_orderLineItemDataSet_calcAggFieldsAdapter extends borland.jbcl.dataset.CalcAggFieldsAdapter {
  2224.   AppDataModule adaptee;
  2225.  
  2226.   AppDataModule_orderLineItemDataSet_calcAggFieldsAdapter(AppDataModule adaptee) {
  2227.     this.adaptee = adaptee;
  2228.   }
  2229.  
  2230.   public void calcAggAdd(ReadRow readRow, ReadWriteRow readWriteRow) throws DataSetException{
  2231.     adaptee.orderLineItemDataSet_calcAggAdd(readRow, readWriteRow);
  2232.   }
  2233.  
  2234.   public void calcAggDelete(ReadRow readRow, ReadWriteRow readWriteRow) throws DataSetException{
  2235.     adaptee.orderLineItemDataSet_calcAggDelete(readRow, readWriteRow);
  2236.   }
  2237.  
  2238. }
  2239.  
  2240. class AppDataModule_productsDataSet_rowFilterAdapter implements borland.jbcl.dataset.RowFilterListener {
  2241.   AppDataModule adaptee;
  2242.  
  2243.   AppDataModule_productsDataSet_rowFilterAdapter(AppDataModule adaptee) {
  2244.     this.adaptee = adaptee;
  2245.   }
  2246.  
  2247.   public void filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  2248.     adaptee.productsDataSet_filterRow(readRow, rowFilterResponse);
  2249.   }
  2250. }
  2251.  
  2252. class AppDataModule_quantityColumn_columnChangeAdapter extends borland.jbcl.dataset.ColumnChangeAdapter {
  2253.   AppDataModule adaptee;
  2254.  
  2255.   AppDataModule_quantityColumn_columnChangeAdapter(AppDataModule adaptee) {
  2256.     this.adaptee = adaptee;
  2257.   }
  2258.  
  2259.   public void changed(DataSet dataSet, Column column, Variant variant) throws DataSetException{
  2260.     adaptee.quantityColumn_changed(dataSet, column, variant);
  2261.   }
  2262. }
  2263.  
  2264.  
  2265. class AppDataModule_orderDataSet_rowFilterAdapter implements borland.jbcl.dataset.RowFilterListener {
  2266.   AppDataModule adaptee;
  2267.  
  2268.   AppDataModule_orderDataSet_rowFilterAdapter(AppDataModule adaptee) {
  2269.     this.adaptee = adaptee;
  2270.   }
  2271.  
  2272.   public void filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  2273.     adaptee.orderDataSet_filterRow(readRow, rowFilterResponse);
  2274.   }
  2275. }
  2276.  
  2277.  
  2278. class AppDataModule_customerDataSet_rowFilterAdapter implements borland.jbcl.dataset.RowFilterListener {
  2279.   AppDataModule adaptee;
  2280.  
  2281.   AppDataModule_customerDataSet_rowFilterAdapter(AppDataModule adaptee) {
  2282.     this.adaptee = adaptee;
  2283.   }
  2284.  
  2285.   public void filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  2286.     adaptee.customerDataSet_filterRow(readRow, rowFilterResponse);
  2287.   }
  2288. }
  2289.  
  2290.  
  2291. class AppDataModule_orderLineItemSizeItemEditor_rowFilterAdapter implements borland.jbcl.dataset.RowFilterListener {
  2292.   AppDataModule adaptee;
  2293.  
  2294.   AppDataModule_orderLineItemSizeItemEditor_rowFilterAdapter(AppDataModule adaptee) {
  2295.     this.adaptee = adaptee;
  2296.   }
  2297.  
  2298.   public void filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  2299.     adaptee.orderLineItemSizeItemEditor_filterRow(readRow, rowFilterResponse);
  2300.   }
  2301. }
  2302.  
  2303. class AppDataModule_orderLineItemColorItemEditor_rowFilterAdapter implements borland.jbcl.dataset.RowFilterListener {
  2304.   AppDataModule adaptee;
  2305.  
  2306.   AppDataModule_orderLineItemColorItemEditor_rowFilterAdapter(AppDataModule adaptee) {
  2307.     this.adaptee = adaptee;
  2308.   }
  2309.  
  2310.   public void filterRow(ReadRow readRow, RowFilterResponse rowFilterResponse) throws DataSetException{
  2311.     adaptee.orderLineItemColorItemEditor_filterRow(readRow, rowFilterResponse);
  2312.   }
  2313. }
  2314.