A Question Abot DIALOGs

A Question Abot DIALOGs

Postby xProgrammer » Tue Apr 08, 2008 10:05 pm

Hi FiveWinnners

I have some questions about DIALOGs that I probably should have asked some time ago, and maybe just shows that I don't quite understand, but here goes:

OK I have DIALOGS (objects of class TDialog) which I create programmatically. In other words my code looks something like this:

Code: Select all  Expand view  RUN
DEFINE DIALOG dlgPATIENT TITLE sTitle SIZE 950, 650
@   3,  1 SAY "Key"         OF dlgPATIENT SIZE 90, 25 
// rest of definition
   @ 60, 51 BUTTON btnQUIT PROMPT "Quit" ACTION ( ::cExitCode := "Q", dlgPATIENT:End() ) OF dlgPATIENT
ACTIVATE DIALOG dlgPATIENT CENTERED


So dlgPATIENT points to an object of class TDialog. I want to use that TDialog object many times. But it seems that dlgPATIENT:End() partly destroys it, because if I try to reuse it later with:

Code: Select all  Expand view  RUN
ACTIVATE DIALOG dlgPATIENT CENTERED


The screen will often come up the second time but not properly and is completely skew wiff by the third time.

I assume I have to call dlgPATIENT:End() to stop its message loop. Is that correct? Is there some other way?

Is anyone out there reusing their DIALOGs in such a manner or do you go through your code that creates them (DEFINE DIALOG) each time you need to use them.

Thanks
xProgrammer
User avatar
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Postby James Bott » Tue Apr 08, 2008 10:49 pm

>Is anyone out there reusing their DIALOGs in such a manner or do you go through your code that creates them (DEFINE DIALOG) each time you need to use them.

You need to call the code each time.

If you need to call it from multiple places, then just put it into a function or a method of a custom class.

James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Postby xProgrammer » Tue Apr 08, 2008 11:02 pm

Hi James

Thanks for the quick reply. It's nice to know that it's not just me.

I do build my DIALOGs in class methods so it's not difficult to rebuild them from scratch, just a call.

However I wonder if this lack of re-usability need be the case? Maybe Antonio could comment on the possibility of being able to keep a defined DIALOG in memory ready to go as it were? It would seem to be a lot more efficient both in terms of re-defining the DIALOG and the resultant garbage collection. Most people doing data entry use just a few screens but use them many times over.

Thanks
Doug
(xProgrammer)
User avatar
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Postby Antonio Linares » Tue Apr 08, 2008 11:15 pm

Doug,

You can hide it ( oDlg:Hide() ) and later on show it ( oDlg:Show() ) again instead of end it.

You may need to create it as non modal, and to simulate modal behavior, disable other windows and dialogs doing oWnd:Disable(). Later on enable them doing oWnd:Enable()
regards, saludos

Antonio Linares
www.fivetechsoft.com
User avatar
Antonio Linares
Site Admin
 
Posts: 42122
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Postby James Bott » Wed Apr 09, 2008 12:10 am

As Antonio points out this may be a lot of work.

Are you having a specific problem you are trying to solve, or are you looking for a solution for a problem that may not exist, or a least may not be significant?

James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Postby xProgrammer » Wed Apr 09, 2008 1:03 am

Hi James

I guess I don't have any major problem in that I can and have written functional software as is.

However something that I thought might have worked and would be more efficient didn't work and I wondered why. I like to understand my programming environment and its limitations.

Interestingly Antonio's suggestions are pretty much in line with the general direction I might want to head in with my software. Whilst my modal dialogs are in place the user can't access the top window menu so any actions pretty much have to be buttons on the DIALOG.

Thinking forward it may well be that I should make my DIALOGs non-modal but where necessary enable only a single instance to be created or active at any time.

One type of functionality is to have a calendar dialog that controls other dialogs pertaining to what is happening on a given day at a given site. For each site and day you might want to display staffing, or bookings, or work done etc.

These different aspects would relate to their own classes and it would be nice to keep the UI aspects of them sitting there.

If you think of it the sort of behaviour I am looking for, it is really in keeping with the spirit of OO. Instantiate an object of class X and you can keep it there for repeated use until you destroy it - I am trying to make the UI component of my classes match that paradigm.

I have programmed for a stateless environment but where I have the luxury of state let me use it.

Thanks for your input. I normally have a fairly pragmatic approach to programming, even if this query seems to be an example of the opposite. Indeed I wonder at the effort here consumed on (for example) the style of buttons, whereas I only need much more basic functionality. There's some very clever coding going on behind some of this, and I guess people are attracted by the latest style of button so programmers feel a need to respond, but in reality its all driven by mass marketing and doesn't really improve software usability at all IMHO.

Regards
Doug
User avatar
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Postby James Bott » Wed Apr 09, 2008 1:24 am

Doug,

>One type of functionality is to have a calendar dialog that controls other dialogs pertaining to what is happening on a given day at a given site. For each site and day you might want to display staffing, or bookings, or work done etc.

>These different aspects would relate to their own classes and it would be nice to keep the UI aspects of them sitting there.

OK, this sounds like a description of a Single Document Interface (SDI) similar to that of Outlook. I am a big fan of SDI.

I generally don't think of this as a dialog issue, although some dialogs may be used inside a folder, window, etc. although generally they don't look or act like dialogs.

>If you think of it the sort of behaviour I am looking for, it is really in keeping with the spirit of OO. Instantiate an object of class X and you can keep it there for repeated use until you destroy it - I am trying to make the UI component of my classes match that paradigm.

With a SDI I just show and hide the screens.

>Thanks for your input. I normally have a fairly pragmatic approach to programming, even if this query seems to be an example of the opposite.

Noted.

>Indeed I wonder at the effort here consumed on (for example) the style of buttons, whereas I only need much more basic functionality. There's some very clever coding going on behind some of this, and I guess people are attracted by the latest style of button so programmers feel a need to respond, but in reality its all driven by mass marketing and doesn't really improve software usability at all IMHO.

You make valid points but you forget that without sales the usability of the software is of little importance. First you must have sales.

Users will buy a product based on the look of its interface. I even find myself leaning in this direction. If I see a screenshot of a program that has a 10 year old interface design, I am much less inclined to buy it that one with an up-to-date interface. One assumes that the functionality may be as old as the interface.

You may be interested in this article:

Magic and Software Design
http://www.asktog.com/papers/magic.html

Also, remember that we programmers are of a different species, Homo Logicus. Users have a completely different view of the world than we do.

Regards,
James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Postby xProgrammer » Wed Apr 09, 2008 3:18 am

Hi James

Thanks so much for your interest.

> OK, this sounds like a description of a Single Document Interface (SDI) similar to that of Outlook. I am a big fan of SDI.

Without really being 100% sure what SDI is exactly I am certainly with you there. When I started with xHarbour/FiveWin (now FiveLinux) I was just concerned with getting some productive software out. I certainly didn't want a full MDI implementation because normally my user would be dealing with 1 patient, 1 booking, 1 report whatever. (When we get to bookings there may be a from slot and a to slot when moving a booking but that still doesn't need or even make great sense in MDI.) But they are likely to be dealing with multiple different objects at the same time (like a patient, a booking, a report, a referring physician etc). So I opted for modal dialogs which made coding pretty much straight forward but as you would know isn't the best fit for the real world that the users are facing and that I am modelling in my software. So SDI here we come!

I have yet to embark down the SDI track so I don't rightly know what problems I will face but I would greatly appreciate your advice when I stumble.

> First you must have sales.

I am only too well aware, both from my own experience and watching what products succeed in the market place. But I have also spent some time working as development manager for a fair sized institution and I know the cost of doing some of these things - not just the money but the extended delivery schedules that often result. I am not criticizing programmers driven by market forces but do wish that we could educate people more. I certainly try to.

Thanks and regards
Doug
(xProgrammer)
User avatar
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Postby Otto » Wed Apr 09, 2008 6:02 am

Hello Doug,

May I ask you for an example screen shot of “a booking“.

As I program hotel management software maybe we can
exchange some ideas.
Regards,
Otto
User avatar
Otto
 
Posts: 6345
Joined: Fri Oct 07, 2005 7:07 pm

Postby xProgrammer » Wed Apr 09, 2008 6:37 am

Hi Otto

I haven't got that far with my software yet.

Bookings are complex in my situation because a single (nuclear medicine) test is in 2 parts (most of them) on the same day both of which require camera time (different amounts) and also doctor time (which is the other limiting resource in general). Plus different tests take different amounts of time so it is complicated to judge if I do 4 less of these can I do two more of some other test. But that is the sort of arrangement I will have to get down to - a kind of trading scheme.

Booking for say a general practitioner (whatever you call your normal day to day doctor) is much simpler because they just allocate standard time slots and book known long consults into 2 or more contiguous slots.

I plan to pre-schedule slots for the more common tests and implement a trading scheme. But ther are further compliactions in that some doctors don't do some tests and the number of patients they are able to see in a day varies. That is not so bad - have a standard schedule for Dr X at site A on a Monday for example. But then the doctors' roster gets changed for some reason - how do I change pre-scheduled slots with some bookings already allocated to these slots?

I am happy to share any design or code I produce but at the moment there isn't anything to share.

I started with the Patient and Patient-File classes as there was a desperate need for off-site archiving and I am working through classes progressively.

I was involved in the early stages of reviewing a design for bookings in a large hospital but the design got far too complicated.

Hopefully I can be of more help shortly.

Regards
Doug
(xProgrammer)
User avatar
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Postby xProgrammer » Wed Apr 09, 2008 6:48 am

Hi Otto

By the way their current (manual paper-based) system was chaotic and not working to anyone's satisfaction so we are improving that to prove up our ideas for improvement before attempting to implement in code.

Regards
Doug
User avatar
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Postby James Bott » Wed Apr 09, 2008 11:32 am

Doug,

>Bookings are complex in my situation because a single (nuclear medicine) test is in 2 parts (most of them) on the same day both of which require camera time (different amounts) and also doctor time (which is the other limiting resource in general). Plus different tests take different amounts of time so it is complicated to judge if I do 4 less of these can I do two more of some other test. But that is the sort of arrangement I will have to get down to - a kind of trading scheme.

This is a classic case for buisness objects that are able to schedule themselves. I highly recommend getting a copy of Buisness Engineering with Object Technology. You can find more about it on my website here:

http://ourworld.compuserve.com/homepage ... rogram.htm

And there is a link to Amazon where you can buy it used (it is out of print) for 1 cent (plus shipping). I would get a copy ASAP. It discusses the kinds of things you are trying to do. On page 122 there is a section called Techniques for Time Management in which he discusses creating a scheduling class and a commitment class. He discusses schedules that require multiple resources, and the use of tenative and firm commitments. This sounds like just what you need.

Coincidentally, I am also working on a medical application. Although my portion of it doesn't deal with scheduling, I have done a lot of work defining the domain (patient, provider, operation, etc.) and trying to understand the interaction between the business objects. So, perhaps the three of us (including Otto) can do some collaboration.

James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Postby xProgrammer » Wed Apr 09, 2008 9:09 pm

Hi James

Thanks for the advice. I look forward to future discussions.

My code consists of a small module that instantiates the required objects, calls for user logon (via a USER_Class) launches a main window with a menu has a couple of utility functions but all the rest is done via objects that interact with each other.

I read your articles before starting and gained a lot from them - part technical but perhaps more so confidence to just "do it". xBase was fine - I had spent quite atime with dBase then Clipper, albeit a long time ago. And I had done some OO work more recently. But OO and xBase was new and strange but actually easy and fun once I got started. I did deviate a little from your methodology in that I have a DATAFILE_Class but that doesn't do automated "gather and scatter" - I think thats what you called it? It does however control the allocation of keys and the standard fields included in all my tables which are:

who last updated the record (user-key)
what action they took [update|inset|delete]
when this occurred (date and time)

I also have, for example, a PATIENT_LIST_Class and a PATIENT_Class even though both are basically dealing with the same data table.

In Australia the government assigns provider numbers per physical location so I have a DOCTOR_LIST_Class, a DOCTOR_Class, a PROVIDER_LIST_Class and a PROVIDER_Class.

Bookings not only involves the complications of scheduling but also the data that you have is imperfect - so that you can't be certain that the patient's name is spelled correctly and we don't have date of birth and what they are booked in for might be incorrect and they might be referred by a doctor who either isn't in your system or whose name they don't know or are uncertain of. Much of this is resolved when they present, but some details (eg the particular test) can't be resolved they are seen by the doctor or in some cases even later depending upon initial test outcomes.

Also in terms of scheduling some tests involve multiple appointments with required timelines between them so you can't just reschedule one part of such a series.

Regards
Doug
User avatar
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Postby James Bott » Thu Apr 10, 2008 2:08 am

Doug,

>I read your articles before starting and gained a lot from them - part technical but perhaps more so confidence to just "do it". xBase was fine - I had spent quite a time with dBase then Clipper, albeit a long time ago. And I had done some OO work more recently. But OO and xBase was new and strange but actually easy and fun once I got started.

Glad to hear all that. I have convinced very few people to start using OOP. It is all very strange at first, but the benefits are tremendous.

>I did deviate a little from your methodology in that I have a DATAFILE_Class but that doesn't do automated "gather and scatter" - I think that's what you called it? It does however control the allocation of keys and the standard fields included in all my tables which are:

>who last updated the record (user-key)
>what action they took [update|inset|delete]
>when this occurred (date and time)

After reading the above I am somewhat concerned that you are missing some OOP understanding.

There is no reason that you couldn't add the above functionality to the existing database class and also get the built in scatter-gather (and all the other good features). You can just subclass TDatabase or my TData class and add your features. May I see your DATAFILE_Class class? Perhaps I can save you some, or lots, of work. BTY, I would not add "_Class" to the class name--it seems redundant.

>I also have, for example, a PATIENT_LIST_Class and a PATIENT_Class even though both are basically dealing with the same data table.

Is you PATIENT_LIST_Class a table and PATIENT_Class a record? Why not call them a Patients class and a Patient class? You really should be using a database class as the basis for a table class. I fear you a making it more difficult than it could be. Is the PATIENT_LIST_Class a subclass of your DATAFILE_Class?

In Australia the government assigns provider numbers per physical location so I have a DOCTOR_LIST_Class, a DOCTOR_Class, a PROVIDER_LIST_Class and a PROVIDER_Class.

Isn't a doctor also a provider? Are you listing them in both files? Or, are you only considering an organization a provider?

The definition we use here is:

Provider- An individual or institution who provides medical care, including a physician, hospital, skilled nursing facility, or intensive care facility.

>Bookings not only involves the complications of scheduling but also the data that you have is imperfect - so that you can't be certain that the patient's name is spelled correctly and we don't have date of birth and what they are booked in for might be incorrect and they might be referred by a doctor who either isn't in your system or whose name they don't know or are uncertain of. Much of this is resolved when they present, but some details (eg the particular test) can't be resolved they are seen by the doctor or in some cases even later depending upon initial test outcomes.

How to handle imperfect data is discussed at length in "About Face The Essentials of User Interface Design," also listed on my website. I'm sure this would also be valuable to you.

Some of the techniques I use with "imperfect" or questionable data is to color the fields yellow and perhaps also popup a tooltip explaining what is commonly placed in the field. Also critical fields are colored pink until the data is entered. And you can flag all records with missing critical data and/or questionable data with a flag so they can later be found and resolved.

>Also in terms of scheduling some tests involve multiple appointments with required timelines between them so you can't just reschedule one part of such a series.

Yes, I realize your scheduling is quite complex--this is all the more reason to use objects to do it. Can you write up just a description of the rules that you need to follow to schedule one of these procedures? I always start with a description of the domain before starting coding. Next is usually an entity-relationship diagram. Then I usually code the very simplest model I can just so I can do test senarios to work out the logic. Making them simple makes them much easier to work with. In your case you could come up with a dozen different test procedures and store them in a file so you can use them to test your scheduler class as you are working on it.

James
User avatar
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Postby xProgrammer » Thu Apr 10, 2008 4:31 am

Hi James

Have to go trail an old car (1928 vintage) 720 kilometres for a friend's wedding so can only make quick reply at this stage.

>Isn't a doctor also a provider? Are you listing them in both files? Or, are you only considering an organization a provider?

A doctor is in effect a different provider for each physical address from which he works, so each provider record points to a doctor record. A doctor record may have zero to many provider records pointing to it. If there are zero records pointing to it then the doctor can't function as a provider.

> Is you PATIENT_LIST_Class a table and PATIENT_Class a record?

Yes

> Why not call them a Patients class and a Patient class?

I like PATIENTLIST because it is unequivocal. I have seen the plural name misused too often.

> I fear you a making it more difficult than it could be. Is the PATIENT_LIST_Class a subclass of your DATAFILE_Class?

No. But PATIENTLIST has the object of type DATAFILE that opened the PT_PATIENT datafile as a property so whilst it isn't a subclass it has many of the benefits. This was a deliberate choice partly to ease data back end migration.

xDATAFILE Class follows. You probably need to see some of the other objects to see how it fits together.

Code: Select all  Expand view  RUN
/******************************************************************************
*                                                                            *
* xDATAFILE Class                                                            *
*                                                                            *
* This class encapsulates the functionality of xBase data files              *
*                                                                            *
******************************************************************************/

CLASS xDATAFILE



DATA WorkArea

DATA KeyRecord

DATA Alias

DATA FileName

DATA MsgName

DATA Index1

DATA Index2

DATA Index3

DATA iNumIndx

DATA bSuccess

DATA sMessage

DATA iKey

DATA sKey

DATA iNumIndx
DATA lConsole
DATA lQuit
DATA lShared



METHOD New( WorkArea, KeyRecord, Alias, FileName, MsgName, Index1, Index2, Index3 ) CONSTRUCTOR

METHOD OpenRaw()

METHOD OpenIndexed()

METHOD OpenFile()

METHOD SetIndices()

METHOD Select()

METHOD LockFile()

METHOD LockRecord()

METHOD Unlock()

METHOD Close()

METHOD GoTo( RecNum )

METHOD GoTop()

METHOD GoBottom()

METHOD AppendBlank()

METHOD BOF()

METHOD EOF()

METHOD GetKey()

METHOD RptKey()

METHOD SetKey( xValue )

METHOD KeyValue()

METHOD Seek( Value )

METHOD SetOrder( Index )

METHOD RecCount()

METHOD Save( CallObj )

METHOD FileInfo()

METHOD Skip( SkipCount )

METHOD LastUpdated()



ENDCLASS



METHOD New( iWorkArea, iKeyRecord, sAlias, sFileName, sMsgName, lConsole, lQuit, Index1, Index2, Index3 ) CLASS xDATAFILE


::lConsole  := lConsole
::lQuit     := lQuit

::WorkArea  := iWorkArea

::KeyRecord := iKeyRecord

::Alias     := sAlias

::FileName  := sFileName

::MsgName   := sMsgName
::lShared   := .T.

::iNumIndx  := PCOUNT() - 7

IF ::iNumIndx < 0

   ::iNumIndx := 0

ENDIF

IF ::iNumIndx > 0

   ::Index1    := Index1

   IF ::iNumIndx > 1

      ::Index2 := Index2

      IF ::iNumIndx > 2

         ::Index3 := Index3

      ENDIF

   ENDIF

ENDIF



RETURN self



METHOD OpenRaw() CLASS xDATAFILE

   LOCAL lbRet

   SELECT ( ::WorkArea )

   lbRet := ::OpenFile()



RETURN lbRet





METHOD OpenIndexed() CLASS xDATAFILE



SELECT ( ::WorkArea )

IF ::OpenFile()
   IF ::lConsole
      ? ::MsgName + " opened in work area " +ALLTRIM( STR( ::WorkArea ) )
   ENDIF

   ::SetIndices()

   RETURN .T.

ENDIF

IF ::lConsole
   ? "Error Opening " + ::sMsgName
ENDIF
IF ::lQuit
   QUIT
ENDIF

RETURN .F.







METHOD OpenFile() CLASS xDATAFILE


IF ::lShared

   USE ( ::FileName ) ALIAS ( ::Alias ) SHARED
  ELSE
   USE ( ::FileName ) ALIAS ( ::Alias ) SHARED
ENDIF

/* LOCAL lsFName

lsFName := ::FileName

OPEN  lsFName */

IF NETERR()

   ? "Error opening " + ::FileName

   RETURN .F.

ENDIF



RETURN .T.





METHOD SetIndices() CLASS xDATAFILE



DO CASE

   CASE ::iNumIndx = 1

      SET INDEX TO ( ::Index1 )
      ?? " Index set to " + ALLTRIM( ::Index1 )

   CASE ::iNumIndx = 2

      SET INDEX TO ( ::Index1 ), ( ::Index2 )
      ?? " Indexes set to " + ALLTRIM( ::Index1 ) + ", " + ALLTRIM( ::Index2 )

   CASE ::iNumIndx = 3

      SET INDEX TO ( ::Index1 ), ( ::Index2 ), ( ::Index3 )
      ?? " Indexes set to " + ALLTRIM( ::Index1 ) + ", " + ALLTRIM( ::Index2 ) + ", " + ALLTRIM( ::Index3 )

ENDCASE



RETURN .T.



METHOD Select

   

   SELECT ( ::WorkArea )



RETURN







METHOD Unlock() CLASS xDATAFILE



   SELECT ( ::WorkArea )

   UNLOCK



RETURN





/*

METHOD LockRecord() CLASS xDATAFILE



   SELECT ( ::WorkArea )



RETURN RLOCK()

*/


METHOD LockRecord() CLASS xDATAFILE

   LOCAL iNumTries
   LOCAL lIsLocked
   SELECT ( ::WorkArea )
   iNumTries := 1
   DO WHILE iNumTries < 6
      lIsLocked := RLOCK()
      IF lIsLocked
         RETURN .T.
      ENDIF
      INKEY(0.5)
      iNumTries += 1
   ENDDO
   MsgInfo( "Unable to lock " + ::FileName )
RETURN .F.






METHOD LockFile() CLASS xDATAFILE



   SELECT ( ::WorkArea )



RETURN FLOCK()







METHOD Close() CLASS xDATAFILE

 

   SELECT ( ::WorkArea )

   CLOSE



RETURN





METHOD AppendBlank() CLASS xDATAFILE



   SELECT ( ::WorkArea )

   APPEND BLANK



RETURN ( !NETERR() )







METHOD BOF() CLASS xDATAFILE



   SELECT ( ::WorkArea )



RETURN BOF()





METHOD EOF() CLASS xDATAFILE



   SELECT ( ::WorkArea )



RETURN EOF()





METHOD GetKey() CLASS xDATAFILE

   

   SELECT ( defWA_KEY )

   IF ::KeyRecord < 1

      RETURN .F.

   ENDIF

   IF ::KeyRecord > RECCOUNT()

      RETURN .F.

   ENDIF

   GOTO ( ::KeyRecord )

   ::iKey := KY_LASTKEY

   ::iKey += 1

   IF RLOCK()

      REPLACE KY_LASTKEY WITH ::iKey

      UNLOCK

      ::sKey := PADL( ALLTRIM( STR( ::iKey)), 16, "0" )

      RETURN .T.

   ENDIF

   

RETURN .F.



METHOD RptKey() CLASS xDATAFILE

   

   LOCAL liKey

   SELECT ( defWA_KEY )

   IF ::KeyRecord < 1

      RETURN 0

   ENDIF

   IF ::KeyRecord > RECCOUNT()

      RETURN 0

   ENDIF

   GOTO ( ::KeyRecord )

   liKey := KY_LASTKEY

   SELECT ( ::WorkArea )

RETURN ( liKey )



METHOD SetKey( xValue ) CLASS xDATAFILE

   ALERT( "SetKey" )

   SELECT ( defWA_KEY )

   IF ::KeyRecord < 1

      RETURN .F.

   ENDIF

   IF ::KeyRecord > RECCOUNT()

      RETURN .F.

   ENDIF

   // ALERT( TYPE( xValue ) )

   GOTO ( ::KeyRecord )

   IF RLOCK()

      REPLACE KY_LASTKEY WITH xValue

      UNLOCK

      ::iKey := xValue

      ::sKey := PADL( ALLTRIM( STR( ::iKey)), 16, "0" )

      RETURN .T.

   ENDIF

   

RETURN .F.





METHOD KeyValue() CLASS xDATAFILE



RETURN ::sKey





METHOD Seek( Value ) CLASS xDATAFILE

   LOCAL llFound



   SELECT ( ::WorkArea )



   SEEK  Value

   llFound := FOUND()

   IF llFound

      // ALERT( "Found"  )

     ELSE

      // ALERT( "Not Found" )

   ENDIF   





RETURN llFound





METHOD SetOrder( Index ) CLASS xDATAFILE



   SELECT ( ::WorkArea )

   SET ORDER TO ( Index )



RETURN





METHOD RecCount() CLASS xDATAFILE

   

   SELECT ( ::WorkArea )

   

RETURN RECCOUNT()



METHOD Save( CallObj ) CLASS xDATAFILE

   

   LOCAL llSuccess



   SELECT ( ::WorkArea )

   CallObj:sLUBy := oUSER:sKey

   CallObj:sLUWhen := oDATETIME:Now()



   IF CallObj:lInsert

      IF ::GetKey()

         CallObj:sKey := ::sKey     

         CallObj:cLUActn := "I"

         llSuccess := ::AppendBlank()
        ELSE
         ALERT("Failed to retrieve key")
      ENDIF

     ELSE

      CallObj:cLUActn := "U"

      llSuccess := ::LockRecord()

   ENDIF

   IF llSuccess

      CallObj:Write()
      dbCOMMIT()

      UNLOCK

   ENDIF

   

RETURN llSuccess





METHOD FileInfo() CLASS xDATAFILE

   

LOCAL lcRet

LOCAL lcLKey

   SELECT ( ::WorkArea )
   lcRet := PADR( ::FileName, 16 ) + " WA= " + LTRIM( STR( ::WorkArea ) ) + " has " + ;
      LTRIM( STR( RECCOUNT() ) ) + " records - updated " + DTOS( LUPDATE() ) + " last key " + STR( ::RptKey() )
/*

   lcRet := PADR( ::FileName, 16 ) + " WA= " + LTRIM( STR( ::WorkArea ) ) + " has " + ;

      LTRIM( STR( RECCOUNT() ) ) + " recs - updated " + DTOS( LUPDATE() ) + "last key "

  IF EMPTY( ::RptKey() )

      lcLKey := "0"

     ELSE

      lcLKey := STR( ::RptKey() )

   ENDIF

   lcRet += lcLKey

*/

RETURN lcRet





METHOD Skip( SkipCount ) CLASS xDATAFILE

   

   LOCAL lnCount

   

   IF PCOUNT() < 1

      lnCount := 1

     ELSE

      lnCount := SkipCount

   ENDIF

   SELECT ( ::WorkArea )

   SKIP ( lnCount )

   

RETURN





METHOD GoTo( RecNum ) CLASS xDATAFILE

   

   SELECT ( ::WorkArea )

   GOTO RecNum

   

RETURN



METHOD GoTop() CLASS xDATAFILE

   

   SELECT ( ::WorkArea )

   GOTO TOP

   

RETURN





METHOD GoBottom() CLASS xDATAFILE

   

   SELECT ( ::WorkArea )

   GOTO BOTTOM

   

RETURN



METHOD LastUpdated() CLASS xDATAFILE

   

   SELECT ( ::WorkArea )

   RETURN DTOS( LUPDATE() )

   

RETURN nil
User avatar
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Next

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: No registered users and 62 guests