*---------------------------------------------------------------------- *-- SEQVALUE.CC.: A SEQUENTIAL value Custom Class Entryfield. *-- Programmer..: Romain Strieff (CIS: 71333,2147) *-- Date........: 02/05/1996 Original *-- ............: 03/08/1997 removed FIELDS bug *-- Notes.......: Custom entryfield that will fill automatically *-- ............: with sequential values when issuing Form.Saverecord() *-- ............: in the form it is placed. Used for InVoice/Order N# *-- ............: etc where the sequence of the numbers must be *-- ............: guaranteed. *-- Written for.: Visual dBASE 5.5a for Windows *-- Calls.......: None *-- Based on....: AUTOINC.CC from Ken Mayer (CIS: 71333,1030) *-- Remarks.....: Your form must use Form.BeginAppend() and *-- ............: Form.SaveRecord() for the CC to work. *-- Comment.....: This CC overrides the Forms SAVERECORD() method. *---------------------------------------------------------------------- CLASS SeqValue(F,N) Of Entryfield(F,N) Custom Protect Onopen,When,Speedtip,enabled This.Speedtip = "SeqValue Custom Control -- You Can't Edit Me!" This.When = {;Return .F.} This.Onopen = Class::SeqValueOnopen this.enabled =.f. Procedure Incrementit *this control MUST have a datalink If Empty(This.Datalink) ?? Chr(7) Msgbox("There is no datalink for this control!","ERROR",16) Return .F. Endif && Empty(This.Datalink) *check if it already has a value If Type("this.value")="N" .And. This.Value > 0 Return .F. && Don't do anything! Endif && Type("this.value")="N" .And. This.Value If Type("this.value")="C" .And. .Not. Empty(This.Value) Return .F. && Don't do anything! Endif && Type("this.value")="C" .And. .Not. Empty *-- if table doesn't exist, create it: *-- check if you don't have any _old_ dbf with the same name!!! cAlias = Alias() If .Not. File("SeqValue.DBF") Select Select() && Next Work Area *structure has been changed so don't use any old version dbf! Create Table "SeqValue.DBF" (Incfield Char (50),Incvalue; Numeric(15,0)) Use SeqValue Excl &&Use Exclusive To Create Index Tag sFields=Set("FIELDS") set fields off *create index tag, so that we can use one record for each *field that needs an incrementing value Index On Upper(Incfield) Tag Incfield *close newly created dbf and return to the saved workarea Use set fields &sFields. Select (Calias) Endif && .Not. File("SeqValue.DBF") *-- open SeqValue.dbf, so we can increment it, then *-- close it as soon as possible: *create exact search expression so that we don't have to *bother with SET EXACT cSeek=Left(Upper(This.Datalink)+Space(50),50) Select Select() && Next Work Area Use SeqValue Order Incfield && Open The Table *wait loop for multiple users the same time Do While .Not. Flock() && Try To Flock It, If Impossible Enddo &&Another User Was Faster *We lock the _file_ instead of the record (RLOCK()) to avoid *problems when 2 users would try to add a new record to SEQVALUE *the same time for the same table field when used the first time. sFields=Set("FIELDS") ? sFields set fields off *search record with this datalink If Seek(cSeek) &&Ok Record Exist *increment value Replace SeqValue->Incvalue With SeqValue->Incvalue+1 && Increment Else *it does not exist, so add a new record Append Blank *save datalink to this record and reset the counter *Here's where the problem could happen if we used record lock *instead on file lock, 2 users might add a record the the same *table-field Replace SeqValue->Incvalue With 1,Incfield With This.Datalink Endif && Seek(Cseek) &&Ok Record Exists Do Case Case Type("this.value")="N" &&It's a numeric field *assign numeric value unchanged This.Value = SeqValue->Incvalue Case Type("this.value")="C" &&It's a char field *construct the right picture clause for this field *@L means leading zeroes Cpicture ="@L "+Replicate("9",Len(This.Value)) *transform to chr type and lenght This.Value= Transform(SeqValue->Incvalue,Cpicture) Otherwise *the user set the datalink to an illegal type field ?? Chr(7) Msgbox("SeqValue.CC only handles N and C datatypes!") Endcase set fields &sFields. Use Select (cAlias) *so we just updated the value, now save it with the rest of *the changes that were done. form.SaveRecord() Return .F. Procedure SeqValueonopen *set the focus to every SeqValuerement control automatically each *time a navigating occurs in the form If Type("form.SeqValue_already_installed")="U" *do this only once for the first SeqValuerement *control on the form. Form.SeqValue_already_installed=.T. *If the form does not have an overriden Saverecord If(Empty(Form.SaveRecord)) Form.SaveRecord=Class::Checkauto Else *otherwise execute both codes Form.AutoSaveRecord=Form.SaveRecord *save reference to new property and Form.SaveRecord={;class::checkauto();form.AutoSaveRecord()} Endif && (Empty(Form.Onnavigate)) Endif && Type("form.SeqValue_already_installed")=" Procedure Checkauto *set focus to each SeqValue object on the form to check *if it has a value *save current control to a variable Oscontrol=Form.Activecontrol *loop through all controls and set focus to all the *SeqValue controls Ocontrol=Form.First Do If "SEQVALUE" = upper(Ocontrol.ClassName) if oControl.pageno=form.pageno Ocontrol.incrementit() endif Endif && "SeqValue" $ Ocontrol.Name Ocontrol=Ocontrol.Before Until Ocontrol.Name==Form.First.Name *set focus to the control that had it before this loop oScontrol.Setfocus() ENDCLASS