Warning, /libraries/kreport/src/Mainpage.dox is written in an unsupported language. File is not indexed.

0001 /**
0002  @mainpage KReport
0003 
0004  %KReport is a framework for the creation and generation of reports in multiple formats.
0005  The %KReport framework implements reporting functionality for creation
0006  of <a href="https://support.office.com/article/e0869f59-7536-4d19-8e05-7158dcd3681c">reports
0007  in MS Access</a> style. They are also similar to <a href="http://www.sap.com/solution/sme/software/analytics/crystal-reports/index.html">
0008  SAP Crystal Reports</a> and <a href="http://help.filemaker.com/app/answers/detail/a_id/13754">
0009  FileMaker reports</a>.
0010 
0011  Reports can be created interactively and programmatically. They can be previewed on screen,
0012  printed, and saved in a variety of formats such as HTML, PDF and OpenDocument.
0013  Reports of this kind offer a way to view, format, and summarize the information.
0014  For example a simple report of contact phone numbers can be prepared, or a more complex
0015  report on sales for different products, regions, and periods of time.
0016 
0017  @section usecases Use Cases
0018 
0019  A report is often filled with information from a database. There are many use cases:
0020  - The data can be displayed, summarized, sorted and grouped
0021  - Totals can be computed and displayed
0022  - Single or multiple records of data can be placed on a page
0023  - Details for individual data records can be placed in a layout
0024  - Labels can be created
0025  - The various report sections, such as title, header or footer, can be sized to suit
0026  - Reports can be generated on demand, thus eliminating saving them in files for further use
0027 
0028  @section concepts Concepts
0029 
0030  There are three main concepts in %KReport: designer, data sources, and rendering objects.
0031  The report designer is a visual tool to create report templates by placing items, such as labels or fields, and setting their properties;
0032  data sources provide the data needed to render the report from its template;
0033  and rendering objects define how to layout and render the report to output devices, such as the screen or a printer.
0034 
0035  @subsection designer Designer
0036 
0037  A report design defines the page size, its margins, and one or more sections that hold items, the smallest unit that tell the engine what data to use and how to render it.
0038  Report designs are saved as XML documents, and can be stored on any medium, for instance files or as part of a KEXI database project, for re-use and transfer.
0039  KReportDesigner is based on the Qt Graphics View framework.
0040 
0041  Internally, it uses the following classes to manipulate the report’s design:
0042 
0043  - KReportDesigner
0044  - KReportDesignerSection
0045  - KReportDesignerSectionDetail
0046  - KReportDesignerSectionDetailGroup
0047  - KReportSectionData
0048  - KReportUnit
0049 
0050  Items, the classes that convert data from sources to rendering objects, are provided through the plugin system, for extensibility, and implement one or more of the following interfaces:
0051 
0052  - KReportAsyncItemBase
0053  - KReportDesignerItemBase
0054  - KReportDesignerItemRectBase
0055  - KReportItemBase
0056  - KReportPluginInterface
0057 
0058  See \ref kreport_item_plugin for more information on how to implement a plugin for a new item.
0059 
0060 
0061  @subsection datasources Data Sources
0062 
0063  Data sources are classes that adapt data from external sources to something that %KReport can work with.
0064  They are somewhat similar in concept to Qt’s QAbstractItemModel, but they instead have to implement one of the following interfaces:
0065 
0066  - KReportDataSource
0067  - KReportScriptSource
0068 
0069  %KReport does not provide any public implementation of data sources and applications must do it themselves.
0070  See \ref kreport_data_source for more information on how to implement a new data source.
0071 
0072 
0073  @subsection renderingobjects Rendering Objects
0074 
0075  The items placed when designing the report’s XML are kind of cookie cutters that define how a particular data is to be rendered on the report’s output.
0076  However, the actual placement and styling of data on a rendered document is done by the following classes:
0077 
0078  - OROCheckBox
0079  - ORODocument
0080  - OROEllipse
0081  - OROImage
0082  - OROLine
0083  - OROPage
0084  - OROPicture
0085  - OROPrimitive
0086  - ORORect
0087  - OROSection
0088  - OROTextBox
0089 
0090  There is a class that takes an XML document with the report’s design from one end, a data source from another, and creates a ORODocument with all rendering object correctly placed inside:
0091 
0092  - KReportPreRenderer
0093 
0094  The actual rendering to an output device, be it the screen or a file, it is performed by classes that inherit from KReportRendererBase, using an instance of KReportRendererContext to pass any information that the renderer requires.
0095  The access to instances of KReportRendererBase it is necessary to use the following class:
0096 
0097  - KReportRendererFactory
0098 
0099 
0100  @section example Simple Example
0101 
0102  The following example loads a report design from an XML file named `report.xml`, pre-renders the report using the data source class in the `examples` directory and, finally, renders the final document to a PDF file named `report.pdf`.
0103 
0104  \code
0105  #include "KReportExampleDataSource.h"
0106  #include <KReportDocument>
0107  #include <KReportPreRenderer>
0108  #include <KReportRenderObjects>
0109  #include <KReportRendererBase>
0110  #include <QApplication>
0111  #include <QDomDocument>
0112  #include <QDomElement>
0113  #include <QFile>
0114  #include <QPainter>
0115  #include <QPdfWriter>
0116 
0117  int main(int argc, char *argv[])
0118  {
0119      QApplication app(argc, argv);
0120 
0121      QFile file("report.xml");
0122      if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
0123          return EXIT_FAILURE;
0124      }
0125      QDomDocument doc;
0126      doc.setContent(QString::fromUtf8(file.readAll()));
0127      QDomElement root = doc.documentElement();
0128 
0129      KReportPreRenderer preRenderer(root.firstChildElement());
0130      if (!preRenderer.isValid()) {
0131          return EXIT_FAILURE;
0132      }
0133      preRenderer.setDataSource(new KReportExampleDataSource);
0134      preRenderer.setName("kreport");
0135      if (!preRenderer.generateDocument()) {
0136          return EXIT_FAILURE;
0137      }
0138 
0139      KReportRendererFactory factory;
0140      KReportRendererBase *renderer = factory.createInstance("screen");
0141      if (!renderer) {
0142          return EXIT_FAILURE;
0143      }
0144 
0145      const KReportDocument *document = preRenderer.reportData();
0146      QPdfWriter pdfWriter("report.pdf");
0147      pdfWriter.setResolution(96);
0148      pdfWriter.setPageLayout(document->pageLayout());
0149 
0150      QPainter painter(&pdfWriter);
0151      KReportRendererContext context;
0152      context.setPainter(&painter);
0153 
0154      ORODocument *preRenderedDocument = preRenderer.document();
0155      int numPages = preRenderedDocument->pageCount();
0156      for (int p = 0; p < numPages; p++) {
0157          if (p > 0) {
0158              pdfWriter.newPage();
0159          }
0160          if (!renderer->render(context, preRenderedDocument, p)) {
0161              return EXIT_FAILURE;
0162          }
0163      }
0164      return EXIT_SUCCESS;
0165  }
0166  \endcode
0167 
0168  The XML could be something like this:
0169 
0170  \verbatim
0171  <!DOCTYPE kexireport>
0172  <kexireport>
0173   <report:content xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
0174                   xmlns:report="http://kexi-project.org/report/2.0"
0175                   xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0">
0176    <report:title>Report</report:title>
0177    <report:grid report:grid-divisions="4"
0178                 report:grid-visible="1"
0179                 report:page-unit="cm"
0180                 report:grid-snap="1" />
0181    <report:page-style report:print-orientation="portrait"
0182                       fo:margin-right="28.346505829687491pt"
0183                       fo:margin-left="28.346505829687491pt"
0184                       report:page-size="A4"
0185                       fo:margin-top="28.346505829687491pt"
0186                       fo:margin-bottom="28.346505829687491pt"
0187    >predefined</report:page-style>
0188    <report:body>
0189     <report:detail>
0190      <report:section fo:background-color="#ffffff"
0191                      report:section-type="detail"
0192                      svg:height="28.346505829689765pt">
0193       <report:field report:item-data-source="project"
0194                     report:z-index="0"
0195                     report:vertical-align="center"
0196                     report:name="field26"
0197                     report:value=""
0198                     svg:width="327.750000343254840pt"
0199                     report:word-wrap="1"
0200                     svg:x="92.250000096614059pt"
0201                     svg:y="6.750000007069322pt"
0202                     svg:height="12.750000013353164pt"
0203                     report:can-grow="1"
0204                     report:horizontal-align="left">
0205        <report:text-style fo:background-color="#ffffff"
0206                           fo:background-opacity="0%"
0207                           fo:letter-spacing="0%"
0208                           fo:font-size="9"
0209                           fo:font-family="Sans Serif"
0210                           fo:foreground-color="#000000"
0211                           style:letter-kerning="true"/>
0212        <report:line-style report:line-style="nopen"
0213                           report:line-weight="1"
0214                           report:line-color="#000000"/>
0215       </report:field>
0216      </report:section>
0217     </report:detail>
0218    </report:body>
0219   </report:content>
0220  </kexireport>
0221  \endverbatim
0222 
0223 
0224  Project's home page: https://community.kde.org/KReport
0225 
0226  @authors
0227  - Adam Pigg <adam@piggz.co.uk> - Maintainer
0228  - Jarosław Staniek <staniek@kde.org> - Developer
0229  - Wojciech Kosowicz <pcellix@gmail.com> - improvements
0230  - Shreya Pandit <shreya@shreyapandit.com> - Web page element
0231  - Radoslaw Wicik <rockford@wicik.pl> - Map element
0232  - OpenMFG, LLC <http://xtuple.com/contact> - original code
0233 
0234  Contributors:
0235  - Friedrich W. H. Kossebau <kossebau@kde.org> - cleanups
0236  - Dag Andersen <danders@get2net.dk> - cleanups
0237 
0238  @licenses
0239  @lgpl
0240 
0241  @page kreport_item_plugin How to Implement a Type Plugin
0242 
0243  This section describes how to create your own item types for KReport by implementing a sample plugin that adds a filled rectangle to the report.
0244 
0245  - \ref kreport_item_plugin_item_base
0246  - \ref kreport_item_plugin_designer_item
0247  - \ref kreport_item_plugin_scripting
0248  - \ref kreport_item_plugin_plugin
0249 
0250  @section kreport_item_plugin_item_base Base Item
0251 
0252  The duties of the base item is to extract values of its properties, such as position or size, from the report’s XML, and to create the rendering primitives to draw from the given data.
0253 
0254  %KReport will give us the XML data in the form of a QDomNode object that only contains the fragment relevant to our item.
0255  In this case, the XML structure will be something like the following:
0256 
0257  \verbatim
0258  <report:rect report:name="rect1"
0259               report:z-index="0"
0260               svg:x="113.386023318759058pt"
0261               svg:y="21.259879372267321pt"
0262               svg:height="40.500000848363968pt"
0263               svg:width="210.000004398924290pt"
0264               fo:background-color="#ffffff"
0265               fo:background-opacity="0%"
0266  >
0267      <report:line-style report:line-style="solid"
0268                         report:line-weight="1"
0269                         report:line-color="#000000"
0270      />
0271  </report:rect>
0272  \endverbatim
0273 
0274  As for the rendering primitives, there are two type of items: these that create them based on a simple value from the data source, for instance a label, and these that use a subquery to extract the data, as is the case for charts;
0275  the former need to implement KReportItemBase::renderSimpleData while the latter need KReportItemBase::renderReportData.
0276  Rendering a rectangle does not need data from a source and will be a simple item that ignores its input.
0277 
0278  \code
0279  #include <KReportItemBase>
0280 
0281  class QDomNode;
0282 
0283  class KReportRectItem : public KReportItemBase
0284  {
0285      Q_OBJECT
0286 
0287  public:
0288      KReportRectItem();
0289      explicit KReportRectItem(const QDomNode &node);
0290      ~KReportRectItem() override;
0291 
0292      QString typeName() const override;
0293      int renderSimpleData(OROPage *page,
0294                           OROSection *section,
0295                           const QPointF &offset,
0296                           const QVariant &data,
0297                           KReportScriptHandler *script) override;
0298 
0299  protected:
0300      void createProperties() override;
0301      QBrush brush() const;
0302      KReportLineStyle lineStyle() const;
0303      QPen pen() const;
0304 
0305      KProperty *m_backgroundColor;
0306      KProperty *m_backgroundOpacity;
0307      KProperty *m_lineColor;
0308      KProperty *m_lineStyle;
0309      KProperty *m_lineWeight;
0310  }
0311 
0312  \endcode
0313 
0314  As we will see later, the default constructor will be used when creating an empty item from the designer and it must create all properties except for the name, size, position, and data source, because these are created by KReportItemBase:
0315 
0316  \code
0317  #include "kreportrectitem.h"
0318  #include <KProperty>
0319  #include <KPropertySet>
0320 
0321  KReportRectItem::KReportRectItem()
0322      : KReportItemBase()
0323  {
0324      createProperties();
0325  }
0326 
0327  void KReportRectItem::createProperties()
0328  {
0329      m_backgroundColor = new KProperty("background-color", QColor(Qt::white), tr("Background color"));
0330 
0331      m_backgroundOpacity = new KProperty("background-opacity", QVariant(0), tr("Background Opacity"));
0332      m_backgroundOpacity->setOption("max", 100);
0333      m_backgroundOpacity->setOption("min", 0);
0334      m_backgroundOpacity->setOption("suffix", "%");
0335 
0336      m_lineWeight = new KProperty("line-weight", 1.0, tr("Line Weight"));
0337      m_lineWeight->setOption("step", 1.0);
0338      m_lineColor = new KProperty("line-color", QColor(Qt::black), tr("Line Color"));
0339      m_lineStyle = new KProperty("line-style", static_cast<int>(Qt::SolidLine), tr("Line Style"), QString(), KProperty::LineStyle);
0340 
0341      propertySet()->addProperty(m_backgroundColor);
0342      propertySet()->addProperty(m_backgroundOpacity);
0343      propertySet()->addProperty(m_lineWeight);
0344      propertySet()->addProperty(m_lineColor);
0345      propertySet()->addProperty(m_lineStyle);
0346  }
0347  \endcode
0348 
0349  As you can see, we create a KProperty object for each property that can be set and then we add them all to the item’s property set, that will manage their life cycle and signals.
0350 
0351  The constructor accepting a QDomNode must extract the properties’ value from it.
0352  Fortunately, KReportItemBase and KReportUtils already contain functions to help us in reading common properties.
0353 
0354  \code
0355  #include <KReportUtils>
0356  #include <QDebug>
0357  #include <QDomNode>
0358 
0359  KReportRectItem::KReportRectItem(const QDomNode &node)
0360      : KReportRectItem()
0361  {
0362      QDomElement element = node.toElement();
0363      nameProperty()->setValue(KReportUtils::readNameAttribute(element));
0364      setZ(KReportUtils::readZAttribute(element));
0365      parseReportRect(element);
0366 
0367      QColor backgroundColor(element.attribute("fo:background-color", "#ffffff"));
0368      m_backgroundColor->setValue(backgroundColor);
0369 
0370      bool ok;
0371      int backgroundOpacity = KReportUtils::readPercent(element, "fo:background-opacity", 100, &ok);
0372      if (ok) {
0373          m_backgroundOpacity->setValue(backgroundOpacity);
0374      }
0375 
0376      QDomNodeList children = element.childNodes();
0377      for (int i = 0; i < children.count(); i++) {
0378          QDomNode node = children.at(i);
0379          QString name = node.nodeName();
0380 
0381          if (name == "report:line-style") {
0382              KReportLineStyle style;
0383              if (parseReportLineStyleData(node.toElement(), &style)) {
0384                  m_lineWeight->setValue(style.weight());
0385                  m_lineColor->setValue(style.color());
0386                  m_lineStyle->setValue(static_cast<int>(style.penStyle()));
0387              }
0388          } else {
0389              qWarning() << "found unknown element while parsing rect element:" << name;
0390          }
0391      }
0392  }
0393  \endcode
0394 
0395  Notice how we can call nameProperty() to set this item’s name even though we did not create that property.
0396  Also, parseReportRect will read the `svg:x`, `svg:y`, `svg:width` and `svg:height` attributes from the node’s element and initialize the corresponding position and size properties that we have inherited from KReportItemBase.
0397 
0398  Now we are ready to render rectangles to the report’s output.
0399  renderSimpleData receives the page and the section that the item needs to render to add the rendering objects to, and must return how much it stretches the section’s height, for instance as a result of wrapping text.
0400  Both are `nullptr` when %KReport is computing the actual section’s height.
0401 
0402  `data` contains the value that the item must render and is given by the data source.
0403  For a rectangle we already got all the information required from the XML and can safely ignore this parameter.
0404 
0405  In this case we only need to create an ORORect object and set all its attributes from the item’s properties.
0406  KReportItemBase::scenePosition and KReportItemBase::sceneSize convert, respectively, the position and size from point units to pixels according to the output’s DPI.
0407 
0408  \code
0409  #include <KReportUnit>
0410  #include <QPointF>
0411  #include <QRectF>
0412 
0413  int KReportRectItem::renderSimpleData(OROPage *page,
0414                                        OROSection *section,
0415                                        const QPointF &offset,
0416                                        const QVariant &data,
0417                                        KReportScriptHandler *script)
0418  {
0419      Q_UNUSED(data)
0420      Q_UNUSED(script)
0421 
0422      auto *rect = new ORORect();
0423      rect->setRect(QRectF(scenePosition(position()) + offset, sceneSize(size())));
0424      rect->setPen(pen());
0425      rect->setBrush(brush());
0426 
0427      if (page) {
0428          page->insertPrimitive(rect);
0429      }
0430      if (section) {
0431          OROPrimitive *clone = rect->clone();
0432          clone->setPosition(scenePosition(position()));
0433          section->addPrimitive(clone);
0434      }
0435      if (!page) {
0436          delete rect;
0437      }
0438 
0439      return 0;
0440  }
0441 
0442  QBrush KReportRectItem::brush() const
0443  {
0444      QColor color = m_backgroundColor->value().value<QColor>();
0445      color.setAlphaF(m_backgroundOpacity->value().toReal() * 0.01);
0446      return QBrush(color);
0447  }
0448 
0449  KReportLineStyle KReportRectItem::lineStyle() const
0450  {
0451      KReportLineStyle style;
0452      style.setWeight(m_lineWeight->value().toReal());
0453      style.setColor(m_lineColor->value().value<QColor>());
0454      style.setPenStyle(static_cast<Qt::PenStyle>(m_lineStyle->value().toInt()));
0455      return style;
0456  }
0457 
0458  QPen KReportRectItem::pen() const
0459  {
0460      KReportLineStyle style = lineStyle();
0461      return QPen(style.color(), style.weight(), style.penStyle());
0462  }
0463  \endcode
0464 
0465  The only remaining bit is to tell %KReport the item‘s name, that will be the basis for its XML tag. That is, `"<report:" + typeName() + ">"`.
0466 
0467  \code
0468  QString KReportRectItem::typeName() const
0469  {
0470      return "rect";
0471  }
0472  \endcode
0473 
0474 
0475  @section kreport_item_plugin_designer_item Designer Item
0476 
0477  The designer item extends from the base item and its duties are to build the XML node that will be placed in the report’s structure, and to draw a preview in the designer’s QGraphicsScene.
0478  This object can start its life with the properties at their default values or by initializing their values from a QDomNode, like the base item does.
0479 
0480  KReportDesignerItemRectBase is a class that extends KReportDesignerItemBase and is used as the base class for items that are “rectangular”.
0481  This, of course, includes our rectangle, but also items such as fields and labels because they define a rectangular area where they will render its data in.
0482  Extending from this class means that we do not need to take care of handling mouse events and can easily draw the item’s resize handles when it is selected.
0483 
0484  \code
0485  #include "kreportrectitem.h"
0486  #include <KReportDesignerItemRectBase>
0487 
0488  class KReportRectDesignerItem : public KReportRectItem, public KReportDesignerItemRectBase
0489  {
0490      Q_OBJECT
0491 
0492  public:
0493      KReportRectDesignerItem(KReportDesigner *designer, QGraphicsScene *scene, const QPointF &pos);
0494      KReportRectDesignerItem(const QDomNode &node, KReportDesigner *designer, QGraphicsScene *scene);
0495      ~KReportRectDesignerItem() override;
0496 
0497      void buildXML(QDomDocument *doc, QDomElement *parent) override;
0498      void paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget = nullptr) override;
0499      KReportRectDesignerItem *clone() override;
0500 
0501  private Q_SLOTS:
0502      void slotPropertyChanged(KPropertySet &set, KProperty &property);
0503 
0504  private:
0505      void init(QGraphicsScene *scene);
0506  };
0507  \endcode
0508 
0509  The constructor accepting a QDomNode is called when the designer loads an existing document and we simply call the base item’s constructor to initialize the properties from the XML node.
0510  The other constructor is called when the user creates a new item on the designer widget and we need to create a default-valuated instance;
0511  notice how we ask KReportDesigner to suggest us a name based on the item’s type name.
0512  In both cases we have to initialize this item in the scene graph and setup a slot that will inform the designer when a property has changed.
0513 
0514  \code
0515  #include "kreportrectdesigneritem.h"
0516  #include <KProperty>
0517  #include <KReportDesigner>
0518  #include <QGraphicsScene>
0519 
0520  KReportRectDesignerItem::KReportRectDesignerItem(KReportDesigner *designer,
0521                                                   QGraphicsScene *scene,
0522                                                   const QPointF &pos)
0523      : KReportRectItem()
0524      , KReportDesignerItemRectBase(designer, this)
0525  {
0526      Q_UNUSED(pos)
0527      init(scene);
0528      qreal size = KReportUnit::parseValue("1cm");
0529      setSceneRect(properRect(*designer, size, size));
0530      nameProperty()->setValue(designer->suggestEntityName(typeName()));
0531  }
0532 
0533  KReportRectDesignerItem::KReportRectDesignerItem(const QDomNode &node,
0534                                                   KReportDesigner *designer,
0535                                                   QGraphicsScene *scene)
0536      : KReportRectItem(node)
0537      , KReportDesignerItemRectBase(designer, this)
0538  {
0539      init(scene);
0540      setSceneRect(KReportItemBase::scenePosition(item()->position()),
0541                   KReportItemBase::sceneSize(item()->size()));
0542  }
0543 
0544  void KReportRectDesignerItem::init(QGraphicsScene *scene)
0545  {
0546      if (scene) {
0547          scene->addItem(this);
0548      }
0549 
0550      connect(propertySet(),
0551              &KPropertySet::propertyChanged,
0552              this,
0553              &KReportRectDesignerItem::slotPropertyChanged);
0554 
0555      setFlags(ItemIsSelectable | ItemIsMovable | ItemSendsGeometryChanges);
0556      setZValue(z());
0557  }
0558 
0559  void KReportRectDesignerItem::slotPropertyChanged(KPropertySet &set, KProperty &property) {
0560      if (property.name() == "name") {
0561         if (!designer()->isEntityNameUnique(property.value().toString(), this)) {
0562             property.setValue(oldName());
0563         } else {
0564             setOldName(property.value().toString());
0565         }
0566      }
0567 
0568      KReportDesignerItemRectBase::propertyChanged(set, property);
0569      if (designer()) {
0570          designer()->setModified(true);
0571      }
0572  }
0573  \endcode
0574 
0575  When the designer wants to write the report’s template in XML, it will call `buildXML()` with the XML document that is creating and the node that needs to be this item’s parent.
0576  Our job is to create the same XML structure that the base item’s constructor accepting a QDomNode can read.
0577  Again, KReportDesignerItemBase has utility functions to help us build the XML of common elements and attributes.
0578 
0579  \code
0580  #include <QDomDocument>
0581  #include <QDomElement>
0582 
0583  void KReportRectDesignerItem::buildXML(QDomDocument *doc, QDomElement *parent)
0584  {
0585      QDomElement entity = doc->createElement("report:" + typeName());
0586 
0587      // properties
0588      addPropertyAsAttribute(&entity, nameProperty());
0589      entity.setAttribute("report:z-index", z());
0590      entity.setAttribute("fo:background-color", m_backgroundColor->value().value<QColor>().name());
0591      entity.setAttribute("fo:background-opacity", QString::number(m_backgroundOpacity->value().toInt()) + '%');
0592 
0593      // bounding rect attributes
0594      buildXMLRect(doc, &entity, this);
0595 
0596      // line Style element
0597      buildXMLLineStyle(doc, &entity, lineStyle());
0598 
0599      parent->appendChild(entity);
0600  }
0601  \endcode
0602 
0603  In fact, we can use this dynamic of `buildXML()` generating the XML node that the constructor can read to implement the required `clone` method.
0604  This method is called by KReportDesigner to copy and paste items, among others.
0605 
0606  \code
0607  KReportRectDesignerItem *KReportRectDesignerItem::clone()
0608  {
0609      QDomDocument doc;
0610      QDomElement parent = doc.createElement("clone");
0611      buildXML(&doc, &parent);
0612      QDomNode node = parent.firstChild();
0613      return new KReportRectDesignerItem(node, designer(), nullptr);
0614  }
0615  \endcode
0616 
0617  The last thing to do is draw the actual item on the designer.
0618  In contrast to KReportItemBase, KReportDesignerItemRectBase is a QGraphicsItem-derived class and must know how to paint itself using a QPainter.
0619  For a rectangle we only have to take the same brush and pen that we use when building a ORORect and paint a rectangle at the current position and size.
0620  KReportDesignerItemRectBase::drawHandles will render the eight small boxes all around the rectangle that allow users to resize our item with the mouse.
0621 
0622  \code
0623  void KReportRectDesignerItem::paint(QPainter *painter,
0624                                     const QStyleOptionGraphicsItem *option,
0625                                     QWidget *widget)
0626  {
0627      Q_UNUSED(option)
0628      Q_UNUSED(widget)
0629 
0630      painter->save();
0631      painter->setPen(KReportRectItem::pen());
0632      painter->setBrush(KReportRectItem::brush());
0633      painter->drawRect(QGraphicsRectItem::rect());
0634      painter->restore();
0635 
0636      drawHandles(painter);
0637 
0638  }
0639  \endcode
0640 
0641  @section kreport_item_plugin_scripting Scripting
0642 
0643  %KReport allows users to write scripts in JavaScript to change items’ properties.
0644  For example, the following script for a report named `example_report` would change the background color of an item named rect1 to the color #abc, and toggle the section’s between #ffffff and #dddddd prior to rendering it:
0645 
0646  \code
0647  function detail() {
0648    var count = 0;
0649    this.OnRender = function() {
0650      count++;
0651      if (count % 2 == 0) {
0652        example_report.section_detail.backgroundColor = "#ffffff";
0653      } else {
0654        example_report.section_detail.backgroundColor = "#dddddd";
0655      }
0656      example_report.section_detail.objectByName("rect1").backgroundColor = "#abc";
0657    }
0658  }
0659  example_report.section_detail.initialize(new detail());
0660  \endcode
0661 
0662  %KReport uses QML’s QJSEngine to run JavaScript and calling `objectByName` from the script will try to create a QObject-derived object that wraps the  item whose name is passed as parameter.
0663  This QObject needs to define Qt properties in order to provide a way to write and read item's property values.
0664  By convention, the scripting class is from the `Scripting` namespace.
0665 
0666  \code
0667  #include <QObject>
0668 
0669  class KReportRectItem;
0670 
0671  namespace Scripting {
0672 
0673  class Rect : public QObject
0674  {
0675      Q_OBJECT
0676      Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
0677      Q_PROPERTY(int backgroundOpacity READ backgroundOpacity WRITE setBackgroundOpacity)
0678      Q_PROPERTY(QColor lineColor READ lineColor WRITE setLineColor)
0679      Q_PROPERTY(int lineStyle READ lineStyle WRITE setLineStyle)
0680      Q_PROPERTY(int lineWeight READ lineWeight WRITE setLineWeight)
0681      Q_PROPERTY(QPointF position READ position WRITE setPosition)
0682      Q_PROPERTY(QSizeF size READ size WRITE setSize)
0683 
0684  public:
0685      explicit Rect(KReportRectItem *item, QObject *parent = nullptr);
0686 
0687      QColor backgroundColor() const;
0688      int backgroundOpacity() const;
0689      QColor lineColor() const;
0690      int lineStyle() const;
0691      int lineWeight() const;
0692      QPointF position() const;
0693      QSizeF size() const;
0694 
0695  public Q_SLOTS:
0696      void setBackgroundColor(const QColor &color);
0697      void setBackgroundOpacity(int opacity);
0698      void setLineColor(const QColor &color);
0699      void setLineStyle(int style);
0700      void setLineWeight(int weight);
0701      void setPosition(const QPointF &position);
0702      void setSize(const QSizeF &size);
0703 
0704  private:
0705      KReportRectItem *m_rect;
0706  };
0707 
0708  }
0709  \endcode
0710 
0711  The implementation is very straightforward and just needs to set or get the item’s property values.
0712 
0713  \code
0714  #include "kreportrectscript.h"
0715  #include "kreportrectitem.h"
0716  #include <KProperty>
0717  #include <QPointF>
0718  #include <QSizeF>
0719 
0720  Scripting::Rect::Rect(KReportRectItem *item, QObject *parent)
0721      : QObject(parent)
0722      , m_rect(item)
0723  {}
0724 
0725  QColor Scripting::Rect::backgroundColor() const
0726  {
0727      return m_rect->m_backgroundColor->value().value<QColor>();
0728  }
0729 
0730  int Scripting::Rect::backgroundOpacity() const
0731  {
0732      return m_rect->m_backgroundOpacity->value().toInt();
0733  }
0734 
0735  QColor Scripting::Rect::lineColor() const
0736  {
0737      return m_rect->m_lineColor->value().value<QColor>();
0738  }
0739 
0740  int Scripting::Rect::lineStyle() const
0741  {
0742      return m_rect->m_lineStyle->value().toInt();
0743  }
0744 
0745  int Scripting::Rect::lineWeight() const
0746  {
0747      return m_rect->m_lineWeight->value().toInt();
0748  }
0749 
0750  QPointF Scripting::Rect::position() const
0751  {
0752      return m_rect->position();
0753  }
0754 
0755  QSizeF Scripting::Rect::size() const
0756  {
0757      return m_rect->size();
0758  }
0759 
0760  void Scripting::Rect::setBackgroundColor(const QColor &color)
0761  {
0762      m_rect->m_backgroundColor->setValue(color);
0763  }
0764 
0765  void Scripting::Rect::setBackgroundOpacity(int opacity)
0766  {
0767      m_rect->m_backgroundOpacity->setValue(opacity);
0768  }
0769 
0770  void Scripting::Rect::setLineColor(const QColor &color)
0771  {
0772      m_rect->m_lineColor->setValue(color);
0773  }
0774 
0775  void Scripting::Rect::setLineStyle(int style)
0776  {
0777      m_rect->m_lineStyle->setValue(qMax(1, qMin(style, 5)));
0778  }
0779 
0780  void Scripting::Rect::setLineWeight(int weight)
0781  {
0782      m_rect->m_lineWeight->setValue(weight);
0783  }
0784 
0785  void Scripting::Rect::setPosition(const QPointF &position)
0786  {
0787      m_rect->setPosition(position);
0788  }
0789 
0790  void Scripting::Rect::setSize(const QSizeF &size)
0791  {
0792      m_rect->setSize(size);
0793  }
0794  \endcode
0795 
0796  Because most of KReportRectItem properties are private, we need to make `Scripting::Rect` a friend class by appending the following at the end of KReportRectItem’s declaration:
0797 
0798  \code
0799  private:
0800    friend class Scripting::Rect;
0801  \endcode
0802 
0803 
0804  @section kreport_item_plugin_plugin Implementing the Plugin Interface
0805 
0806  We already have all the actors ready
0807  — the base item class, the designer’s, and the class that allows changing its properties from scripts —,
0808  but we need a way to somehow tell %KReport that they exist.
0809  This is done by implementing the KReportPluginInterface interface.
0810 
0811  \code
0812  #include <KReportPluginInterface>
0813 
0814  class Q_DECL_EXPORT KReportRectPlugin : public KReportPluginInterface
0815  {
0816      Q_OBJECT
0817 
0818  public:
0819      explicit KReportRectPlugin(QObject *parent, const QVariantList &args = QVariantList());
0820      ~KReportRectPlugin() override;
0821 
0822      QObject *createRendererInstance(const QDomNode &element) override;
0823      QObject *createDesignerInstance(const QDomNode &element,
0824                                      KReportDesigner *designer,
0825                                      QGraphicsScene *scene) override;
0826      QObject *createDesignerInstance(KReportDesigner *designer,
0827                                      QGraphicsScene *scene,
0828                                      const QPointF &pos) override;
0829  #ifdef KREPORT_SCRIPTING
0830      QObject *createScriptInstance(KReportItemBase *item) override;
0831  #endif
0832  };
0833  \endcode
0834 
0835  KReportPluginInterface::createRendererInstance is called when there is the need to instantiate a base item for rendering the report.
0836  It is given the QDomNode from the report’s XML template of this item.
0837 
0838  \code
0839  #include "kreportrectitem.h"
0840 
0841  QObject *KReportRectPlugin::createRendererInstance(const QDomNode &element)
0842  {
0843      return new KReportRectItem(element);
0844  }
0845  \endcode.
0846 
0847  Likewise, KReportPluginInterface::createDesignerInstance is called to instantiate a designer item.
0848  As we saw above, the designer item can be needed when loading an XML document or when the user creates a new item in the designer widget, that is why there are two different signatures for this method.
0849 
0850  \code
0851  #include "kreportrectdesigneritem.h"
0852 
0853  QObject *KReportRectPlugin::createDesignerInstance(const QDomNode &element,
0854                                                     KReportDesigner *designer,
0855                                                     QGraphicsScene *scene)
0856  {
0857      return new KReportRectDesignerItem(element, designer, scene);
0858  }
0859 
0860  QObject *KReportRectPlugin::createDesignerInstance(KReportDesigner *designer,
0861                                                     QGraphicsScene *scene,
0862                                                     const QPointF &pos)
0863  {
0864      return new KReportRectDesignerItem(designer, scene, pos);
0865  }
0866  \endcode
0867 
0868  The last class we need to instantiate is the QObject-derived object used in scripts.
0869  The method receives the item to wrap as a parameter.
0870  Due to the dynamic nature of JavaScript, we need to cast it to the type of our item and make sure it is correct.
0871 
0872  \code
0873  #ifdef KREPORT_SCRIPTING
0874 
0875  #include "kreportrectscript.h"
0876 
0877  QObject *KReportRectPlugin::createScriptInstance(KReportItemBase *item)
0878  {
0879      auto rect = qobject_cast<KReportRectItem *>(item);
0880      if (!rect) {
0881          return nullptr;
0882      }
0883      return new Scripting::Rect(rect);
0884  }
0885 
0886  #endif
0887  \endcode
0888 
0889  The last thing required to implement this interface is to create a plugin factory.
0890  It can be done with the K_PLUGIN_CLASS_WITH_JSON macro, that expects the name of the class extending KReportPluginInterface and the name of a JSON file with valid KPlugin metadata.
0891  It is also necessary to include the source code generated by the Qt MOC in the plugin’s implementation file in order to compile the generated factory code.
0892 
0893  \code
0894  #include "kreportrectplugin.h"
0895 
0896  K_PLUGIN_CLASS_WITH_JSON(KReportRectPlugin, "rect.json")
0897 
0898  KReportRectPlugin::KReportRectPlugin(QObject *parent, const QVariantList &args)
0899      : KReportPluginInterface(parent, args)
0900  {}
0901 
0902  KReportRectPlugin::~KReportRectPlugin() {}
0903 
0904  #include "kreportrectplugin.moc"
0905  \endcode
0906 
0907  The JSON file must have all necessary KPlugin metadata.
0908  Also, "Version" must be set to the major and minor component of %KReport’s stable version.
0909  For example, in %KReport 3.2.1 "Version" must be set to "3.2".
0910 
0911  Lastly, the JSON file must contain a "X-KDE-PluginInfo-LegacyName" property with the exact same value as the return value of KReportItemBase::typeName or %KReport would fail to find the plugin when reading XML templates or creating new items in the designer.
0912 
0913  \verbatim
0914  {
0915          "KPlugin": {
0916                  "Authors": [
0917                          {
0918                                  "Email": "author@hosting.suffix",
0919                                  "Name": "Proud Author"
0920                          }
0921                  ],
0922                  "Category": "",
0923                  "Description": "Rectangle element for Reports",
0924                  "Icon": "draw-rectangle",
0925                  "Id": "org.kde.kreport.rect",
0926                  "License": "LGPL",
0927                  "Name": "Rect",
0928                  "Version": "3.3"
0929          },
0930          "X-KDE-PluginInfo-LegacyName": "rect",
0931          "X-KReport-PluginInfo-Priority": "100"
0932  }
0933  \endverbatim
0934 
0935  The last piece you need for a complete item plugin is a `CMakeLists.txt` that compiles and installs the plugin.
0936  The `CMakeLists.txt` looks like the following:
0937 
0938  \verbatim
0939  find_package(ECM 1.8.0 NO_MODULE REQUIRED)
0940  set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
0941 
0942  include(KDEInstallDirs)
0943  include(KDECMakeSettings NO_POLICY_SCOPE)
0944  include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
0945 
0946  set(CMAKE_INCLUDE_CURRENT_DIR ON)
0947  set(CMAKE_CXX_STANDARD 11)
0948  set(CMAKE_CXX_STANDARD_REQUIRED ON)
0949 
0950  find_package(Qt5 5.4.0 COMPONENTS Core REQUIRED)
0951  find_package(KReport 3.2.90 NO_MODULE REQUIRED)
0952 
0953  set(kreportrectplugin_SRCS
0954    kreportrectdebug.cpp
0955    kreportrectdesigneritem.cpp
0956    kreportrectitem.cpp
0957    kreportrectplugin.cpp
0958  )
0959 
0960  if (KREPORT_SCRIPTING)
0961      list(APPEND kreportrectplugin_SRCS
0962        kreportrectscript.cpp
0963      )
0964  endif(KREPORT_SCRIPTING)
0965 
0966  add_library(KReportRectPlugin MODULE ${kreportrectplugin_SRCS})
0967  target_link_libraries(KReportRectPlugin PRIVATE Qt5::Core KReport)
0968 
0969  install(TARGETS KReportRectPlugin DESTINATION ${KDE_INSTALL_PLUGINDIR}/kreport3)
0970  \endverbatim
0971 
0972  Now you can compile the type plugin and install it.
0973  Once done, the new plugin should be available for every application using %KReport.
0974  In applications that utilize the Report Designer, Items toolbar should also offer the new item type.
0975 
0976 
0977  @page kreport_data_source How to Implement a Data Source
0978 
0979  This section describes how to implement a data source for %KReport.
0980  As an example, this data source will simply wrap a QAbstractTableModel and will keep the current row in an attribute.
0981  It is the most simple data source that does not sort its data.
0982 
0983  \code
0984  #include <KReportDataSource>
0985  #include <QPointer>
0986 
0987  class QAbstractTableModel;
0988 
0989  class KReportTableModelDataSource : public KReportDataSource
0990  {
0991  public:
0992     explicit KReportTableModelDataSource(QAbstractTableModel *model);
0993     ~KReportTableModelDataSource() override;
0994 
0995     bool open() override;
0996     bool close() override;
0997     bool moveNext() override;
0998     bool movePrevious() override;
0999     bool moveFirst() override;
1000     bool moveLast() override;
1001     qint64 at() const override;
1002     qint64 recordCount() const override;
1003     int fieldNumber(const QString &field) const override;
1004     QStringList fieldNames() const override;
1005     QVariant value(int pos) const override;
1006     QVariant value(const QString &field) const override;
1007     QStringList dataSourceNames() const override;
1008 
1009  private:
1010     qint64 m_currentRow;
1011     QPointer<QAbstractTableModel> m_model;
1012  };
1013  \endcode
1014 
1015  The constructor already receives the model with all the data that we need to extract, therefore in this case there is nothing to open or close.
1016 
1017  \code
1018  #include "kreporttablemodeldatasource.h"
1019  #include <QAbstractTableModel>
1020 
1021  KReportTableModelDataSource::KReportTableModelDataSource(QAbstractTableModel *model)
1022      : KReportDataSource()
1023      , m_currentRow(0)
1024      , m_model(&model)
1025  {}
1026 
1027  KReportTableModelDataSource::~KReportTableModelDataSource() {}
1028 
1029  bool KReportTableModelDataSource::open()
1030  {
1031      // Nothing to do.
1032      return true;
1033  }
1034 
1035  bool KReportTableModelDataSource::close()
1036  {
1037      // Nothing to do.
1038      return true;
1039  }
1040  \endcode
1041 
1042  Next we will manage the current row by implementing the next, previous, first, and last methods.
1043  Those methods are called by %KReport when traversing the data source within a report’s section.
1044 
1045  \code
1046  bool KReportTableModelDataSource::moveNext()
1047  {
1048      if (m_currentRow >= recordCount() - 1) {
1049          return false;
1050      }
1051      m_currentRow++;
1052      return true;
1053  }
1054 
1055  bool KReportTableModelDataSource::movePrevious()
1056  {
1057      if (m_currentRow <= 0) {
1058          return false;
1059      }
1060      m_currentRow--;
1061      return true;
1062  }
1063 
1064  bool KReportTableModelDataSource::moveFirst()
1065  {
1066      m_currentRow = 0;
1067      return true;
1068  }
1069 
1070  bool KReportTableModelDataSource::moveLast()
1071  {
1072      m_currentRow = recordCount() - 1;
1073      return true;
1074  }
1075 
1076  qint64 KReportTableModelDataSource::at() const
1077  {
1078      return m_currentRow;
1079  }
1080  \endcode
1081 
1082  %KReport needs to know how many rows there are in the data source.
1083 
1084  \code
1085  qint64 KReportTableModelDataSource::recordCount() const
1086  {
1087      return m_model->rowCount();
1088  }
1089  \endcode
1090 
1091  It also needs to know the field count for each record, their names, and a way to reference them.
1092  All records need to have the same number of fields, exactly like the rows of a QAbstractTableModel.
1093  In this case, the field names will correspond to column’s names, and will use them as keys;
1094  the default behaviour of KReportDataSource::fieldKeys() is to return the output of KReportDataSource::fieldNames().
1095 
1096  \code
1097  QStringList KReportTableModelDataSource::fieldNames() const
1098  {
1099      QStringList names;
1100      for (int i = 0; i < m_model->columnCount(); i++) {
1101          names << m_model->headerData(i, Qt::Horizontal).toString();
1102      }
1103      return names;
1104  }
1105 
1106  int KReportTableModelDataSource::fieldNumber(const QString &field) const
1107  {
1108      for (int i = 0; i < m_model->columnCount(); i++) {
1109          if (m_model->headerData(i, Qt::Horizontal).toString() == field) {
1110              return i;
1111          }
1112      }
1113      return -1;
1114  }
1115  \endcode
1116 
1117  %KReport will need to be able to read the value of a given field.
1118  The field is always in the current record and can be referenced by the key — the column’s name in this case — or by its position.
1119  Therefore we need to handle both cases.
1120 
1121  \code
1122  QVariant KReportTableModelDataSource::value(int pos) const
1123  {
1124      return m_model->data(m_model->index(m_currentRow, pos));
1125  }
1126 
1127  QVariant KReportTableModelDataSource::value(const QString &field) const
1128  {
1129      return value(fieldNumber(field));
1130  }
1131  \endcode
1132 
1133  The last remaining method to implement is for data sources that can retrieve data from multiple sources.
1134  In this case there is one possible source, the QAbstractTableModel, and have nothing to return.
1135 
1136  \code
1137  QStringList KReportTableModelDataSource::dataSourceNames() const
1138  {
1139      return QStringList();
1140  }
1141  \endcode
1142 
1143  Our data source is now ready to be used to render reports.
1144 */
1145 // DOXYGEN_SET_PROJECT_NAME = KReport
1146 // DOXYGEN_SET_IGNORE_PREFIX = KReport
1147 // DOXYGEN_SET_EXCLUDE_PATTERNS += *_p.h
1148 // DOXYGEN_SET_EXCLUDE_PATTERNS += */editors/* */plugins/*
1149