Standard warning when called for delete default button

For some reason the default button on standard warning when called for delete defaults to Yes. My users complain that they sometimes accidently delete records because of this
I figured the code in ABError.clw : ErrorClass.TakeUser PROCEDURE is responsible for this. When I changed the default button as follows

ErrorClass.TakeUser PROCEDURE
  CODE
    IF SELF.Msg(SELF.SubsString(),SELF.GetErrorBufferTitle(),ICON:Question, |
       Button:Yes+Button:No,BUTTON:No,SELF.MsgStyle) = Button:Yes
      RETURN Level:Benign
    ELSE
      RETURN Level:Cancel
    END

However I was wandering if there is any solution that does not require changes in Libsrc folder as when my app will be compiled on another copy of Clarion or I will simply upgrade to newer build my changes will be overwritten and it will default back to Yes button. I can also copy modified ABError.clw to my app directory, but there may be a problem if there are any changes in that file in new build and my app will still use old version. My concern is that I will simply forget about this change after a while.
How do you make sure records are not accidently deleted? Is there a way of overriding this method inside my app ?

I did it by deriving the ErrorClass and overriding the TakeUser method.

MyErrorClass.TakeUser PROCEDURE
  CODE
    If Self.GetErrorBufferId() = Msg:ConfirmDelete
      IF MESSAGE(Self.SubsString(),SELF.GetErrorBufferTitle(),ICON:Question, |
         Button:Yes+Button:No,BUTTON:No,0) = Button:Yes
        RETURN Level:Benign
      ELSE
        RETURN Level:Cancel
      END
    Else
      Return Parent.TakeUser()
    End

You can control which error class your app uses in the Global Properties of the App.

I dislike a Message() with Yes/No buttons that require reading the body to understand the question. I.e. does YES Delete? I like the button labels to make it obvious.

If you want to improve things maybe separate Delete Message code with Buttons of Delete / Keep:

Maybe this code?

ErrorClass.TakeError PROCEDURE(SHORT Id)
  CODE
    SELF.StoreErrorEntry(Id)
    CASE Id                         !Carl: Special handling for certain Error IDs
    OF Msg:ConfirmDelete
       RETURN SELF.Take:Msg:ConfirmDelete() 
    END

    CASE SELF.GetErrorBufferFatality()
    OF Level:Benign
    ....

ErrorClass.Take:Msg:ConfirmDelete PROCEDURE()  !New Method for Delete
    CODE
!     IF SELF.Msg(SELF.SubsString(),SELF.GetErrorBufferTitle(),ICON:Question, |
    IF SELF.Msg('Are you sure you want to delete the highlighted record?', |
                'Confirm Delete',ICON:Question, |
                'Delete Record|Keep Record',2,SELF.MsgStyle) = 1 THEN 
      RETURN Level:Benign
    ELSE
      RETURN Level:Cancel
    END
!FYI
!       USHORT(Msg:ConfirmDelete)
!       BYTE(Level:User)
!       PSTRING('Confirm Delete')
!       PSTRING('Are you sure you want to delete the highlighted record?')

That would be perfect, I agree Yes/No buttons may be confusing, so I would rather have meaningful buttons as you suggest.

The problem is that I never derived a class in Clarion . I can see there is a derive checkbox but never done it myself, especially with built in classes. Do you have any examples how to do it?
I found some Clarion Live video by Bruce but cannot open it.

Or what I learned from an example of Steve Parker, via the UpdateForm:

ThisWindow.PrimeUpdate PROCEDURE
ReturnValue          BYTE,AUTO
! Start of "WindowManager Method Data Section"
! [Priority 5000]

! End of "WindowManager Method Data Section"
  CODE
  ! Start of "WindowManager Method Executable Code Section"
  ! [Priority 4500]
      If ThisWindow.Request = DeleteRecord
          Message(' you are going to delete the following Dossier: '& |
                  '| ' & |
                  '| ' & CLIP(DOSS:DossierName) & |
                  '| [ Click Ok ] and make a choice','Remove dossier',ICON:Exclamation)
      End

And at:

 ! Parent Call
  ReturnValue = PARENT.PrimeUpdate()
  ! [Priority 5001]
     If ThisWindow.Request = DeleteRecord and ThisWindow.Response = RequestCompleted
        Message('Dossier'&' '&clip(DOSS:DossierNaam)&' '&'is deleted','delete') 
     End

Hi Greg,

It’s fairly easy to derive most ABC Classes. This example, is using Rick’s code, create yourself two files, saving to clarion\accessory\libsrc\win

MyErrorClass.inc


!ABCIncludeFile

OMIT('_EndOfInclude_',_MyErrorClassPresent_)
_MyErrorClassPresent_ EQUATE(1)
  INCLUDE('ABError.inc'),ONCE

MyErrorClass                    CLASS(ErrorClass),TYPE,MODULE('MYERRORCLASS.CLW'),LINK('MYERRORCLASS.CLW',_ABCLinkMode_),DLL(_ABCDllMode_)
TakeUser                        PROCEDURE,BYTE,Derived,PROC,PROTECTED
                              END

_EndOfInclude_                                

MyErrorClass.clw

   MEMBER

  INCLUDE('MyErrorClass.INC'),ONCE

  MAP
  END

MyErrorClass.TakeUser PROCEDURE
  CODE
    If Self.GetErrorBufferId() = Msg:ConfirmDelete
      IF MESSAGE(Self.SubsString(),SELF.GetErrorBufferTitle(),ICON:Question, |
         Button:Yes+Button:No,BUTTON:No,0) = Button:Yes
        RETURN Level:Benign
      ELSE
        RETURN Level:Cancel
      END
    Else
      Return Parent.TakeUser()
    End  

Then in Global Properties->Actions->Classes, Refresh Application Builder Class Information, then press the General Button, on the Error Manager Dropdown, locate MyErrorClass and select it.

Then recompile, and your derived class will now be the one used in your application

NOTE You will need to change this in all applications of a multi dll solution.

I hope this helps.
Mark

FWIW, that OMIT() stuff kind of pre-dates the ONCE syntax and isn’t really necessary (if you use ONCE, that is :-), which usually is the case nowadays )

Hi Jeff,

I agree, but didn’t want to confuse the matter as the ErrorClass has the old style.
Mark

Thanks, Mark. Nice example.
Additionally, if you start going down this road of deriving your own classes from the base ABC classes, you can write a global template that will change your Apps to use your classes.

#AT(%BeforeGenerateApplication)
   #Set(%ErrorManagerType, 'MyErrorClass')
#ENDAT

Combing Mark’s override of .TakeUser() with my desire for named buttons I would suggest below that any ID can have custom buttons for Yes/No so choices are better understood.

MyErrorClass.TakeUser PROCEDURE() !,DERIVED
Button1 PSTRING(32) !Text for YES
Button2 PSTRING(32) !Text for NO
DefaultBtn BYTE(1)  !Default to YES like the original
  CODE
  CASE Self.GetErrorBufferId()
  OF Msg:ConfirmDelete        !Confirm Delete - Are you sure you want to delete the highlighted record?  
  OROF Msg:RetryDelete        !Record Delete Error - An error was experienced deleting this record. Do you want to try to delete it again?
       Button1='Delete Record'
       Button2='Keep Record'   
       DefaultBtn=2  
  OF Msg:SaveRecord           !Save Record - Do you want to save the changes to this record?
       Button1='Save Record'
       Button2='Discard'   
       DefaultBtn=1
  OF Msg:RetrySave            !Record Update Error - An error was experienced changing this record. Do you want to try to save again?
       Button1='Retry Save'
       Button2='Discard'   
       DefaultBtn=1       
  OF Msg:AddAnother           !Record Added - This record has been added to the file. Do you want to add another record?
       Button1='Add Again'
       Button2='Close Form'   
       DefaultBtn=2
  ELSE
      Return Parent.TakeUser()  !Call Base Class Yes/No Message
  END
  IF ~Button1 THEN Button1='&Yes'.      !Did above code fail to set values
  IF ~Button2 THEN Button2='&No'.
  IF MESSAGE(Self.SubsString(),SELF.GetErrorBufferTitle(),ICON:Question, |
     Button1 &'|'& Button2, DefaultBtn, SELF.MsgStyle) = 1 THEN 
    RETURN Level:Benign
  ELSE
    RETURN Level:Cancel
  END

Note that your original change for all Defaults to be NO would have a negative affect on some like “Save Record” would default to NO where YES is the better default.

Thanks all for this feedback,

It complains about SELF.MsgStyle
Invalid use of PRIVATE data - C:\Clarion11.1\libsrc\win\MYERRORCLASS.CLW:46,46
Removing OMIT lines does not make difference,

but when I removed this message parameter works like charm

I pushed the current code to GitHub GitHub - yaitblog/myerrorclass: Custom class derived from ABError Clarion Class · GitHub

I added MyErrorClass.trn for easy translation or customization of these button texts.

It does help. Thanks a lot. I have been previously adding methods to eg. WindowManager in the IDE and called ThisWindow.MyNewMethod, but never actually done it this way overriding a method. Nice and useful.