/*----------------------------------------------------------------------------*/ /* */ /* Copyright (c) 2011-2014 Rexx Language Association. All rights reserved. */ /* */ /* This program and the accompanying materials are made available under */ /* the terms of the Common Public License v1.0 which accompanies this */ /* distribution. A copy is also available at the following address: */ /* https://www.oorexx.org/license.html */ /* */ /* Redistribution and use in source and binary forms, with or */ /* without modification, are permitted provided that the following */ /* conditions are met: */ /* */ /* Redistributions of source code must retain the above copyright */ /* notice, this list of conditions and the following disclaimer. */ /* Redistributions in binary form must reproduce the above copyright */ /* notice, this list of conditions and the following disclaimer in */ /* the documentation and/or other materials provided with the distribution. */ /* */ /* Neither the name of Rexx Language Association nor the names */ /* of its contributors may be used to endorse or promote products */ /* derived from this software without specific prior written permission. */ /* */ /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */ /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */ /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */ /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */ /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */ /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */ /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */ /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */ /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */ /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* */ /*----------------------------------------------------------------------------*/ /* ooDialog User Guide Exercise08 Support - Model v02-00 24May13 ---------------- A superclass for the Model-View framework. v01-00 09Aug12: First version. 11Jan13: Commented-out "say"s. 31Jan13: Store model's data in 'myData'. 27Feb13: Commented-out some "say" instructions. v02-00 24May13: Added inherit from the 'Component' mixin. = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */ ::REQUIRES "Support\Component.rex" /*============================================================================*/ ::CLASS 'Model' PUBLIC INHERIT Component ::ATTRIBUTE wantList CLASS PUBLIC -- for List subclasses ::ATTRIBUTE myData /*---------------------------------------------------------------------------- newInstance - must be invoked by subclass. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ::METHOD newInstance CLASS PUBLIC expose noDataError -- .true if data not found. use strict arg instanceName --say ".Model-newInstance-01: instanceName =" instanceName -- Check that the model's Data object is up and running. If not, then return .false: if noDataError = .true then return .false -- Now get the name of the Data component (FredModel or FredListModel --> FredData): -- Get my root name (i.e. the root name of the subclass): className = self~objectName -- objectName for a class Foo is "The Foo class" className = className~upper() -- When class name is in quotes, then it's mixed case. -- Upper here to make everthing upper case for parse var. -- Handling Forms: -- If this is a "Form" then there's no data to get (the user will provide -- the data). So just create the Form Model (e.g. Order Form) and return. -- Assume that the instance name is the Form Number (e.g. for an OrderForm, -- the Form Number will be the new Order Number). p = className~pos("FORM") if p > 0 then do -- if this is a "Form" component. instData = .Directory~new instData[formNumber] = instanceName formObject = self~new(instData) formObject~myData = instData -- store instance data for subclasses to access. --say ".Model-newInstance-011: formObj, instanceName =" formObject||"," instanceName return formObject end -- End of Handling Forms. -- If there's "LIST" in the name, then set "get all" for the file access -- (as opposed to the default of "get 1 record") getAllRecords = .false p = className~pos("LIST") if p > 0 then getAllRecords = .true -- if there's a "LIST" in the name, strip it out 'cos an xListModel gets data from xData parse var className . root1 "MODEL" . parse var root1 root "LIST" dataClassName = root||"Data" --say ".Model-newInstance-02, dataClassName =" dataClassName -- Get the id of Data component: objMgr = .local~my.ObjectMgr --say ".Model-newInstance-03: objMgr =" objMgr myDataId = objMgr~getComponentId(dataClassName, "The") if myDataId = .false then do -- if instantiation failed say ".Model-newInstance-04: getting ID of Data Class failed." noDataError = .true return .false end -- Got my data id, now get data for this model instance. -- But distinguish between Entity Models and List Models - the former needs -- a single record, the latter a group of records. -- say ".Model-newInstance-05a: getAllRecords =" getAllRecords if getAllRecords then instData = myDataId~getFile() -- returns a 2D array else instData = myDataId~getRecord(instanceName) -- a directory -- say ".Model-newInstance-05b: array dimensions: =" instData~dimension if instData = .false then return .false -- if ID (key) not found -- All is well, then make new instance: --say ".Model-newInstance-06: instData =" instData id = self~new(instData) id~myData = instData --say ".Model-newInstance-07: instData =" id return id /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /*---------------------------------------------------------------------------- getInstanceName - For an "anonymous" instance only (e.g. CustomerList) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ::METHOD getInstanceName CLASS PUBLIC expose anonInstanceName if anonInstanceName = "ANONINSTANCENAME" then anonInstanceName = 1 else anonInstanceName = anonInstanceName + 1 return anonInstanceName /*---------------------------------------------------------------------------- query - returns a Model's data. Standard protocol: Accept a .nil, directory, array, or string of names (case-sensitive). if .nil then return all fields; else return values for the names in the directory, array, or string. String is assumed to be data names separated by one or more spaces. All returns are a Directory containing names and values. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ ::METHOD query PUBLIC use arg dataNames --say "Model-query-01: dataNames:" dataNames dirReturn = .Directory~new select when dataNames = .nil | dataNames = "" then return self~myData when dataNames = "DATANAMES" then return self~myData -- Caller is requesting specific data items: when dataNames~isa(.Directory) then do --say "Model-query-02; dataNames =" dataNames do i over dataNames dirReturn[i] = self~myData[i] end end when dataNames~isa(.Array) then do do i over dataNames dirReturn[i] = self~myData[i] end end when dataNames~isa(.String) then do dataNames = dataNames~strip n = dataNames~countStr(" ")+1 do i = 1 to n parse var dataNames name " " dataNames if name = " " then iterate -- ignore extraneous leading spaces. dirReturn[name] = self~myData[name] end end otherwise return .false end return dirReturn /*============================================================================*/ /*============================================================================*/