Home Subreports
New Blog Posts: Merging Reports - Part 1 and Part 2

Dynamic Supreport Loading

edited March 2006 in Subreports
Hi support-team,

Continuing on the story to get DSL working _with_ datapipelines in the
enduser environment.
Using StartOfMainReport() to load the template file is in these cases too
late.
After testing a bit, the Loaded() method seems a place to load the template
file. Early enough to get the datapipeline working if you want to print or
preview a report e.g. run-time.

The problem now is how to get the subreport to show the correct content 'at
design-time' e.g. in the designer.

The way it works now: The user adds a template component to it's report and
assigns the DefaultProperty with the template name. This is the name of a
report (template) that is found in the database (rb_item) in a
system-folder. While typing this template name my event handler is called. I
update the designer with the new template name which is reflected by the
subreport tabs.

1. I would like to have some event if he leaves the edit field. At that time
I could load the template from the database and check if the template name
is correct. Another way would be to create a custom form called from the
context menu of the template component (but I haven't looked into that L)

2. When the user types an incorrect template name I generate an exception.
When debugging this exception is raised but at run-time it looks like this
exception is eaten by RB resulting in an empty report. The user has no way
to correct his error.

3. How do I notify the designer that something in my DSL has changed so the
'do you want so save the changes dialog' is showed?

If it would clarify things I could e-mail you the component.

Using RB10.01 and D7 Pro.

Regards,
Jeroen R?ttink

Comments

  • edited March 2006
    Update:

    I created a Design Control class for the template component.

    1. Is solved. New question is can I disable the defaultproperty control?
    Setting it to '' doesn't disable it. No big deal.
    2. Solved. Replaced exception with with a messagebox that is only displayed
    by the designerclass.
    3. Solved by calling PropertyChange() when a custom property changes

    A new problem arises however. The basis is that in the Loaded() method a
    call is made to LoadFromDatabase() to load the content of the subreport
    including any DADE objects. The existing subreport content is removed an
    replaced by the new layout. The old DADE objects however are not removed.
    The same effect when loading a subreport in the designer by the way.

    How can I replace existing DADE objects by the new ones if the name matches?
    Any other working solution is of cause also welcome.


    Regards,
    Jeroen R?ttink



  • edited March 2006

    1. One option is access the DataView via the DataPipeline.DataView property.

    2. There is a single TdaDataModule for the entire report. When a subreport
    is loaded, its DataViews are merged with the main report's TdaDataModule.
    You could perhaps access the TdaDataModule and then iterate over its
    DataViews[] array.

    uses
    daDataModule: TdaDataModule;

    lDataModule := daGetDataModule(myReport);





    Best regards,

    Nard Moseley
    Digital Metaphors
    www.digital-metaphors.com
  • edited March 2006
    Nard,

  • edited March 2006

    Looks good.

    The QueryDataView classes created by the Query Designer and Query Wizard
    always have a single DataPipeline, so DataPipelines[0] is what you want.

    However a DataView can have multiple datapipelines. For an example, see
    RBuilder\Demos\EndUser\Custom DataViews.




    Best regards,

    Nard Moseley
    Digital Metaphors
    www.digital-metaphors.com
  • edited March 2006
    Now testing with 10.02 but I don't think that changes stuff.

    Situation:

    Report containing a template (Dynamic Loading Subreport) with an attached
    dataview. This dataview is also referenced by a dbtext object on the
    mainreport. As part of the dynamic loading process I remove dataviews that
    already exist in the report and re-assign datapipelines of rcl components
    that reference the old, to be removed, dataviews.
    This works ok the first time I preview a report from the report explorer but
    not the second time. The code that looks for and replaces datapipelines is
    not finding any rcl components that should be reassigned while it is finding
    these components the first time.

    What is different the second run?

    procedure ReLinkReportComponents( aReport : TppCustomReport;
    aOldDataView, aNewDataView :
    TdaDataView );
    var liBand: Integer;
    liObject: Integer;
    lObject: TppComponent;
    lDataView: TdaDataView;
    liDataPipeline: integer;
    begin
    for liBand := 0 to aReport.BandCount-1
    do begin
    for liObject := 0 to aReport.Bands[liBand].ObjectCount-1
    do begin
    lObject := aReport.Bands[liBand].Objects[liObject];
    if lObject.IsDataAware
    then begin
    if ( lObject.DataPipeline.DataView = aOldDataView ) // <== always
    false the second run
    then begin
    // find the index of the used datapipeline (a dataview can
    // have more datapipelines. see RBuilder\Demos\EndUser\Custom
    DataViews)
    lDataView := TdaDataView(lObject.DataPipeline.DataView);
    liDataPipeline := lDataView.IndexOfChild(lObject.DataPipeline);
    try
    lObject.DataPipeline :=
    aNewDataView.DataPipelines[liDataPipeline];
    except
    lObject.DataPipeline := nil;
    end;
    end;
    end;
    // call this method recursively if it's a subreport
    if lObject is TppSubReport
    then ReLinkReportComponents( (lObject as TppSubReport).Report,
    aOldDataView, aNewDataView );
    end;
    end;
    end;

    Regards,
    Jeroen R?ttink


  • edited March 2006

    I do not know what the difference is.

    Where are you calling your ReLinkReportComponents method from?



    Best regards,

    Nard Moseley
    Digital Metaphors
    www.digital-metaphors.com
  • edited March 2006
    From the Loaded() method.

  • edited March 2006

    Each time you select Preview, the Designer saves the report definition to a
    temp stream and then reloads the report definition from stream when you
    leave the Preview workspace. This is necessary because a report can contain
    RAP code that changes the report layout during generation.



    Best regards,

    Nard Moseley
    Digital Metaphors
    www.digital-metaphors.com
  • edited March 2006
    Yes but it's not when I use the designer. I have a TppReport in my
    application that loads the report from database. If this report contains a
    dynamic loading subreport with DADE objects it seems that the second time I
    load this report into a ppReport object, it gives errors. I can sent you my
    code if this would help. This is an error I then sometimes get:

    Access violation at address FFFFFFFF. Read of address FFFFFFFF.
    Exception class: EAccessViolation
    Exception address: FFFFFFFF
    ----------------------------------------------------------------------------
    ------------------------
    Stack list
    [FFFFFFFF]
    [00404AD7] System.@HandleAnyException + $33
    [006F6FF0] ppRelatv.TppRelative.SetParent + $24
    [008F6526] daQueryDataView.TdaQueryDataView.SetParent + $A
    [006F6AEC] ppRelatv.TppRelative.Destroy + $18
    [008DAA39] daDataView.TdaCustomDataView.Destroy + $1D
    [008F5E82] daQueryDataView.TdaQueryDataView.Destroy + $4A
    [0091B2B0] daIBExpress.TdaIBXQueryDataView.Destroy (Line 639,
    "daIBExpress.pas" + 4) + $7
    [0042FDF2] Classes.TComponent.DestroyComponents + $46
    [0042FBF7] Classes.TComponent.Destroy + $47
    [0048C31B] Controls.TControl.Destroy + $9B
    [00404570] System.TObject.FreeInstance + $C
    [0040497A] System.@ClassDestroy + $2
    [00433E8E] Graphics.TBrush.Destroy + $1E
    [0048F9B1] Controls.TWinControl.Destroy + $B9
    [004A72A8] Forms.TScrollingWinControl.Destroy + $28
    [004A82A3] Forms.TCustomForm.Destroy + $AB
    [004A82BE] Forms.TCustomForm.Destroy + $C6
    [006E3E0A] uJRForm.TjrForm.Destroy (Line 83, "uJRForm.pas" + 7) + $7
    [00A04D65] uPrinten.TDlgPrinten.Destroy (Line 158, "uPrinten.pas" + 8) + $7
    [004045B8] System.TObject.Free + $8
    [00A06A7F] uIPrintProvider.TPrintProvider.Print (Line 183,
    "uIPrintProvider.pas" + 14) + $3
    [00A06AA8] uIPrintProvider.TPrintProvider.Print (Line 186,
    "uIPrintProvider.pas" + 17) + $1C
    [00A228EC] udbOutline.TdbOutline.actPrintExecute (Line 564, "udbOutline.pas"
    + 4) + $8

    Also the message 'Cannot generate report. ORGANISATIE: Could not open
    DataSet. Database not assigned' is sometimes generated. This is always the
    second run. First run after start-up always works correct.


  • edited March 2006

    Can you create an example that uses the DBDemos data?

    I installed Interbase 7.5, after installing D2006 and Interbase will not
    run.



    Best regards,

    Nard Moseley
    Digital Metaphors
    www.digital-metaphors.com
This discussion has been closed.