Hi Rick,
I'm a licensed user of XFRX and have been using that library via the classes implemented in wwPDF. I'm having some fun (not) with "printing" barcode labels to a dedicated label printer (Dymo LabelWriter 450) and in the process dug into this class a bit. (Printing is a bit of a misnomer as we basically just generate PDFs for any VFP reports.) I noticed that there are actually 2 variants of the XFRX implementation in wwPDF
so I've been experimenting with both. In particular I got interested in wwXFRX9
as that uses the more modern OO assisted report engine. There are 2 things I discovered when I tried to use an instance of that class.
1 - I was getting an error on the call to the PrintReport method. A little digging in the XFRX docs indicates that when running in listener mode, it's necessary to have a SET PROCEDURE call to a prg they supply called utilityreportlistener
. Once I added that to my code, the PDF was generated. While I could have that in my code before calling DO wwPDF
I'll put forth the proposition that this is a dependency of using wwXFRX9 and should be in a method of that sub-class (init?).
************************************************************************
* wwXFRX9 :: Init
*********************************
*** Function: using XFRX in listener mode requires Eqeus' utilityreportlistener
*** to be in the procedure list
************************************************************************
FUNCTION Init
LOCAL llRetval AS Boolean
TRY
SET PROCEDURE TO utilityreportlistener ADDITIVE
llRetval=.t.
CATCH TO lowwXFRX9InitError
llRetval=.f.
FINALLY
ENDTRY
RETURN m.llRetval
ENDFUNC
* wwXFRX9 :: Init
2 - The other thing I noticed was that the PrintReport method does not check the extension of the report/label and always executes REPORT FORM
. So I made a couple of changes in my local wwPDF to distinguish between reports and labels.
*!* - rk - 2020-8-26 - add extension check
IF !this.lResetPageNo AND UPPER(JUSTEXT(m.lcReport))=[FRX] && norest not supported by label form
m.lcExtraReportClauses = m.lcExtraReportClauses + ' noreset'
ENDIF
this.lResetPageNo = .f.
IF this.nParamsRetVal = 0
*this.oPDF.setEmbeddingType(this.nEmbeddingType)
*!* - rk - 2020-8-26 - add branch for label form vs report form
IF UPPER(JUSTEXT(m.lcReport))=[LBX]
LABEL FORM (m.lcReport) OBJECT this.oPDF &lcExtraReportClauses
ELSE
REPORT FORM (m.lcReport) OBJECT this.oPDF NOPAGEEJECT &lcExtraReportClauses
ENDIF
The odd thing was that even though REPORT FORM
was being used with a label, XFRX still did its magic. So honestly, I don't know how necessary that is.
It can't be a dependency of the library because it would be pulled in (or tried to be pulled in) when compiling wwPDF.prg
as part of a project. It should be documented though.
I didn't actually write that library nor tested it - Keith Hackett did.
Can you verify exactly what the requirements are as I don't have a recent version of XFRX here.
The class also mentions dependencies on the FoxPro FFC Report classes - are those actually required?
I've added:
*** The following support library has to be available:
*** SET PROCEDURE TO UtilityReportListener.prg
to the header of the class.
I also wonder if the behavior of XFRX9 class is any different than the other class. Personally I would prefer to use the old one if there aren't additional dependencies.
+++ Rick ---
Right, of course. I suppose it could be implemented via macro expansion in which case the build issue could be avoided. OTOH if I'm using this then I'll have that prg in my project. Do none of the other PDF variants supported have dependencies? In any case I'll just invoke it in my code.
Using the 9 version allows taking advantage of the OO assisted report engine features. As best I understand it, that does create a dependency on the ability to create VFP report listeners, which does mean including the FFC stuff. According to Eqeus' docs, if you don't use these more advanced report engine features, like dynamic properties, there's a stripped down version of the prg that can be used without adding the VCXs.
Here's a PDF of a label generated with the base class:
And here's a PDF using the 9 variant:
As you can see, the second one looks a lot more like what the expected output.
What do you think about incorporating my change for LABEL FORM
vs REPORT FORM
?
It looks to me that the first report is treated like a report while the second runs as a label. Not sure what it takes for the old library to work off a label sized report. I never really used XFRX beyond just making it work so not enough info to go on...
I've added your Label change the wwXFRX9
class.
+++ Rick ---
Thanks for the update, Rick. I assume this will be in the next release (.16?)
Yes
Hi Rick,
I was doing some testing with 7.20 yesterday and noticed one change I had recommended for wwPDF was not included; the extension check for adding noreset to m.lcExtraReportClauses.
*!* - rk - 2020-8-26 - add extension check
IF !this.lResetPageNo AND UPPER(JUSTEXT(m.lcReport))=[FRX] && noreset not supported by label form
m.lcExtraReportClauses = m.lcExtraReportClauses + ' noreset'
ENDIF
Not sure I follow.
Can't you just add noreset
to the lcExtraReportClauses
? That's what that's there for also look at lResetPageNo
which sets the NORESET
flag.
this.lSuccessful = .t.
TRY
IF TYPE('this.oPDF') # 'O'
this.cErrorMsg = [Unable to create report generator instance]
this.lSuccessful = .f.
ELSE
m.lcExtraReportClauses = IIF(EMPTY(lcExtraReportClauses),'',lcExtraReportClauses)
IF TYPE('m.lcOutputFile') = 'C' AND !EMPTY(m.lcOutputFile);
AND NOT m.lcOutputFile == this.cOutputName
this.cOutputName = m.lcOutputFile
this.nParamsRetVal = .f.
ENDIF
IF TYPE('this.nParamsRetVal') # 'N'
this.SetParams(m.llAppend)
ENDIF
IF !this.lResetPageNo
m.lcExtraReportClauses = m.lcExtraReportClauses + ' noreset'
ENDIF
this.lResetPageNo = .f.
IF this.nParamsRetVal = 0
*this.oPDF.setEmbeddingType(this.nEmbeddingType)
IF UPPER(JUSTEXT(m.lcReport))=[LBX]
LABEL FORM (m.lcReport) OBJECT this.oPDF &lcExtraReportClauses
ELSE
REPORT FORM (m.lcReport) OBJECT this.oPDF NOPAGEEJECT &lcExtraReportClauses
ENDIF
SET PRINTER TO default
ELSE
this.cErrorMsg = [Unable to set report parameters, error code ] + TRANSFORM(this.nParamsRetVal)
this.lSuccessful = .f.
ENDIF
this.oPDF.Finalize()
ENDIF
this.oPDF.Finalize()
this.oPdf = null
CATCH TO oError
this.lSuccessful = .f.
this.cErrorMsg = oError.Message
ENDTRY
Looks to me the noreset
is in there with:
IF !this.lResetPageNo
m.lcExtraReportClauses = m.lcExtraReportClauses + ' noreset'
ENDIF
+++ Rick ---