User Functions
User functions let the host application take part in report generation with its own C++ code. A user function is an object of a class derived from NCReportUserFunction, registered in the report under a string ID. Any report item can refer to a user function by this ID; the engine then calls the function every time the item is refreshed, and the function can modify the item before it is printed: change its text, color, font or other properties, based on report data or on any information available in the application.
User functions are useful when a rule is too complex, too slow or simply not practical to express as a script expression, or when it depends on application state that is not available to the report as data, such as business logic in C++, user permissions or runtime settings.
The NCReportUserFunction Class
The public interface of the class, declared in ncreportuserfunction.h, is:
class NCReportUserFunction
{
public:
NCReportUserFunction();
virtual ~NCReportUserFunction();
enum UserAccess { Invisible=0, ReadOnly, ReadWrite };
void setUserAccess( UserAccess access );
UserAccess userAccess() const;
virtual void updateValue( NCReportItem* item, NCReportOutput* output,
NCReportEvaluator* evaluator) = 0;
};
updateValue()-
The only method you must implement. Its arguments are:
-
item: the report item being refreshed. Useitem→objectType()(for exampleNCReportItem::Label,NCReportItem::Field,NCReportItem::Image) to check the item type before casting it to the concrete item class. -
output: the current report output. -
evaluator: the report evaluator. Its publicevaluate(QString&)method replaces data source ($D{…}), parameter ($P{…}) and variable ($V{…}) tokens in a string with their current values, so the function can read the current record.
-
setUserAccess()/userAccess()-
Control how the Function ID field is presented in the Designer’s item property dialogs when the item refers to this function:
ReadWrite(the default) leaves the field editable,ReadOnlymakes it read-only, andInvisiblehides it.
When the Function Is Called
The report engine refreshes every item of a section each time the section is rendered, by calling the item’s updateValue() method; this happens before the item’s Print When expression is evaluated. At the end of this step, if the item has a function ID and a user function is registered with that ID, the engine calls the user function’s updateValue() with the item.
The item’s own value evaluation runs before the user function for field, text and barcode items, so the function sees the item already updated for the current record.
For field items, note that the displayed text is formatted from the field value during this evaluation; a user function is therefore best suited to changing the field’s appearance (colors, font) rather than its value. For static text (label) items, the printed text can be replaced with setText().
Assigning a Function to an Item
Each report item has a Function ID property, found among the Advanced Options at the bottom of the item property dialogs (next to the item ID and zone ID). In the report definition it is stored in the funcID attribute:
<field id="F1" zValue="0" posX="0.000" posY="0.000" width="30.000" height="4.762"
resource="datasource" type="num" ftype="ds" funcID="lateHighlight">days_late</field>
User functions are not called from script expressions or from data source expressions; they are attached to items only through the function ID. If no function is registered with the given ID, the property is ignored.
Implementing and Registering a User Function
The following example changes the text color of a field to red when the order belonging to the current record is late. The number of late days is read from the current record of the orders data source.
Declaration and implementation:
#include "ncreportuserfunction.h"
#include "ncreportfielditem.h"
#include "ncreportevaluator.h"
class LateOrderHighlighter : public NCReportUserFunction
{
public:
void updateValue(NCReportItem* item, NCReportOutput* output,
NCReportEvaluator* evaluator) override
{
Q_UNUSED(output)
if (item->objectType() != NCReportItem::Field)
return;
QString daysLate("$D{orders.days_late}");
evaluator->evaluate(daysLate); (1)
NCReportFieldItem* field = static_cast<NCReportFieldItem*>(item);
field->setForeColor(daysLate.toInt() > 0 ? Qt::red : Qt::black);
}
};
| 1 | The data reference is replaced by the current value. |
|
The same item object is used for every record. If the function changes a property under some condition, it should also set it back in the other case, as the example does with the black color. |
Registration with NCReport::addUserFunction():
LateOrderHighlighter lateHighlight; (1)
NCReport *report = new NCReport(this);
report->setReportFile("orders.ncr");
report->addUserFunction("lateHighlight", &lateHighlight);
report->runReportToPreview();
| 1 | The function object must live while the report runs. |
The report does not take ownership of the function object, so you are responsible for keeping it alive while the report runs and for deleting it afterwards.
Using user functions in the Designer
If your application embeds the NCReport Designer, register the functions in the Designer main window with NCRDMainWindow::addUserFunction(). The functions registered there are passed to the report engine when a report is run from the Designer, so the preview shows their effect:
LateOrderHighlighter lateHighlight;
window.addUserFunction("lateHighlight", &lateHighlight);
Custom toolbar actions created with addCustomToolAction() accept an optional user function ID as their last argument; items created with such an action get this function ID automatically. Combined with setUserAccess(NCReportUserFunction::ReadOnly) or Invisible, this lets you provide predefined item types whose function binding cannot be changed by report designers.
Script-Based Functions
User functions are a C++ mechanism. Reports can also contain reusable logic written in script, which requires no application code:
- JavaScript functions in expressions
-
A script expression (for example, a field with the Script expression source type) can define JavaScript functions and call them in the same expression. The
Javascript_Function_Demo.ncrdemo report pads a number with leading zeros this way:function pad(n, width, z) { z = z || '0'; n = n + ''; return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n; } pad($D{DataSource1.col2},6)The data source token is replaced with the current value before the script runs.
- Stored scripts
-
Script code used in several places can be stored in the report with the Script Editor and referenced with the
$S{scriptId}token. See the Script Editor chapter. - Data source and value functions
-
Data source expressions support built-in functions such as
rowCount(),isAvailable()orMID(n,m)(see theFunctionsDemo.ncrdemo report). These are described in the Data/Script Expressions chapter.