File indexing completed on 2024-04-28 04:42:09

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2001-2007 by OpenMFG, LLC <info@openmfg.com>
0003  * Copyright (C) 2007-2010 by Adam Pigg <adam@piggz.co.uk>
0004  * Copyright (C) 2011-2017 Jarosław Staniek <staniek@kde.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Lesser General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2.1 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014  * Lesser General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Lesser General Public
0017  * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
0018  */
0019 
0020 #include "KReportDesigner.h"
0021 #include "KReportDesign_p.h"
0022 #include "KReportDesignerItemLine.h"
0023 #include "KReportDesignerSection.h"
0024 #include "KReportDesignerSectionDetail.h"
0025 #include "KReportDesignerSectionDetailGroup.h"
0026 #include "KReportDesignerSectionScene.h"
0027 #include "KReportDesignerSectionView.h"
0028 #include "KReportPageSize.h"
0029 #include "KReportPluginInterface.h"
0030 #include "KReportPluginManager.h"
0031 #include "KReportPluginMetaData.h"
0032 #include "KReportPropertiesButton.h"
0033 #include "KReportRuler_p.h"
0034 #include "KReportSection.h"
0035 #include "KReportSectionEditor.h"
0036 #include "KReportUtils.h"
0037 #include "KReportUtils_p.h"
0038 #include "KReportZoomHandler_p.h"
0039 #include "kreport_debug.h"
0040 #ifdef KREPORT_SCRIPTING
0041 #include "KReportScriptSource.h"
0042 #endif
0043 
0044 #include <KPropertyListData>
0045 
0046 #include <KStandardShortcut>
0047 #include <KStandardGuiItem>
0048 #include <QLayout>
0049 #include <QDomDocument>
0050 #include <QVBoxLayout>
0051 #include <QGridLayout>
0052 #include <QGraphicsSceneMouseEvent>
0053 #include <QMenu>
0054 #include <QPointer>
0055 #include <QIcon>
0056 #include <QAction>
0057 #include <QMouseEvent>
0058 #include <QMessageBox>
0059 
0060 //! Also add public method for runtime?
0061 const char ns[] = "http://kexi-project.org/report/2.0";
0062 
0063 static QDomElement propertyToElement(QDomDocument* d, KProperty* p)
0064 {
0065     QDomElement e = d->createElement(QLatin1String("report:" + p->name().toLower()));
0066     e.appendChild(d->createTextNode(p->value().toString()));
0067     return e;
0068 }
0069 
0070 //
0071 // define and implement the ReportWriterSectionData class
0072 // a simple class to hold/hide data in the ReportHandler class
0073 //
0074 class ReportWriterSectionData
0075 {
0076 public:
0077     ReportWriterSectionData() {
0078         selected_x_offset = 0;
0079         selected_y_offset = 0;
0080         mouseAction = MouseAction::None;
0081     }
0082     virtual ~ReportWriterSectionData() {
0083     }
0084 
0085     enum class MouseAction {
0086         None = 0,
0087         Insert = 1,
0088         Grab = 2,
0089         MoveStartPoint,
0090         MoveEndPoint,
0091         ResizeNW = 8,
0092         ResizeN,
0093         ResizeNE,
0094         ResizeE,
0095         ResizeSE,
0096         ResizeS,
0097         ResizeSW,
0098         ResizeW
0099     };
0100 
0101     int selected_x_offset;
0102     int selected_y_offset;
0103 
0104     MouseAction mouseAction;
0105     QString itemToInsert;
0106 
0107     QList<KReportDesignerItemBase*> copy_list;
0108     QList<KReportDesignerItemBase*> cut_list;
0109 };
0110 
0111 //! @internal
0112 class Q_DECL_HIDDEN KReportDesigner::Private
0113 {
0114 public:
0115     explicit Private(KReportDesigner *designer);
0116 
0117     ~Private()
0118     {
0119         delete dataSource;
0120     }
0121 
0122     void init(const QDomElement *xml);
0123 
0124     void updateCurrentUnit() {
0125         QString u = unit->value().toString();
0126         KReportUnit newUnit = KReportUnit(KReportUnit::symbolToType(u));
0127         if (newUnit.isValid()) {
0128             currentUnit = newUnit;
0129         } else {
0130             currentUnit = DEFAULT_UNIT;
0131         }
0132 
0133         if (u == QLatin1String("dm")) {
0134             gridDivisions->setOption("max", 100);
0135         } else {
0136             gridDivisions->setOption("max", 10);
0137             if (gridDivisions->value().toInt() > 10) {
0138                 gridDivisions->setValue(10, KProperty::ValueOption::IgnoreOld);
0139             }
0140         }
0141     }
0142 
0143 #ifdef KREPORT_SCRIPTING
0144     void updateScripts();
0145 #endif
0146 
0147     KReportDesigner * const q;
0148 
0149     QGridLayout *grid;
0150     KReportRuler *hruler;
0151     KReportZoomHandler zoomHandler;
0152     QVBoxLayout *vboxlayout;
0153     KReportPropertiesButton *pageButton;
0154 
0155     QGraphicsScene *activeScene = nullptr;
0156 
0157     ReportWriterSectionData sectionData;
0158 
0159     KReportDesignerSection *reportHeader = nullptr;
0160     KReportDesignerSection *pageHeaderFirst = nullptr;
0161     KReportDesignerSection *pageHeaderOdd = nullptr;
0162     KReportDesignerSection *pageHeaderEven = nullptr;
0163     KReportDesignerSection *pageHeaderLast = nullptr;
0164     KReportDesignerSection *pageHeaderAny = nullptr;
0165 
0166     KReportDesignerSection *pageFooterFirst = nullptr;
0167     KReportDesignerSection *pageFooterOdd = nullptr;
0168     KReportDesignerSection *pageFooterEven = nullptr;
0169     KReportDesignerSection *pageFooterLast = nullptr;
0170     KReportDesignerSection *pageFooterAny = nullptr;
0171     KReportDesignerSection *reportFooter = nullptr;
0172     KReportDesignerSectionDetail *detail = nullptr;
0173 
0174     //Properties
0175     KPropertySet set;
0176     KPropertySet *itemSet;
0177     KProperty *title;
0178     KProperty *pageSize;
0179     KProperty *orientation;
0180     KProperty *unit;
0181     KProperty *customPageSize;
0182     KProperty *leftMargin;
0183     KProperty *rightMargin;
0184     KProperty *topMargin;
0185     KProperty *bottomMargin;
0186     KProperty *showGrid;
0187     KProperty *gridDivisions;
0188     KProperty *gridSnap;
0189     KProperty *labelType;
0190 #ifdef KREPORT_SCRIPTING
0191     KProperty *script;
0192 #endif
0193 
0194     KReportUnit currentUnit;
0195 
0196     //Actions
0197     QAction *editCutAction;
0198     QAction *editCopyAction;
0199     QAction *editPasteAction;
0200     QAction *editDeleteAction;
0201     QAction *sectionEdit;
0202     QAction *parameterEdit;
0203     QAction *itemRaiseAction;
0204     QAction *itemLowerAction;
0205 
0206     qreal pressX = -1;
0207     qreal pressY = -1;
0208     qreal releaseX = -1;
0209     qreal releaseY = -1;
0210 
0211     bool modified = false; // true if this document has been modified, false otherwise
0212 
0213     QString originalInterpreter; //Value of the script interpreter at load time
0214     QString originalScript; //Value of the script at load time
0215 
0216     KReportDataSource *dataSource = nullptr;
0217 #ifdef KREPORT_SCRIPTING
0218     KReportScriptSource *scriptSource = nullptr;
0219 #endif
0220 
0221 private:
0222     void loadXml(const QDomElement &data);
0223 };
0224 
0225 KReportDesigner::Private::Private(KReportDesigner *designer)
0226     : q(designer), currentUnit(DEFAULT_UNIT_TYPE)
0227 {
0228 }
0229 
0230 // (must be init() instead of ctor because we are indirectly depending on initialized KReportDesigner::d here)
0231 void KReportDesigner::Private::init(const QDomElement *xml)
0232 {
0233     KReportPluginManager::self(); // this loads icons early enough
0234 
0235     q->createProperties();
0236     q->createActions();
0237 
0238     grid = new QGridLayout(q);
0239     grid->setSpacing(0);
0240     grid->setMargin(0);
0241     grid->setColumnStretch(1, 1);
0242     grid->setRowStretch(1, 1);
0243     grid->setSizeConstraint(QLayout::SetFixedSize);
0244 
0245     vboxlayout = new QVBoxLayout();
0246     vboxlayout->setSpacing(0);
0247     vboxlayout->setMargin(0);
0248     vboxlayout->setSizeConstraint(QLayout::SetFixedSize);
0249 
0250     //Create nice rulers
0251     hruler = new KReportRuler(nullptr, Qt::Horizontal, zoomHandler);
0252     hruler->setUnit(DEFAULT_UNIT);
0253 
0254     pageButton = new KReportPropertiesButton;
0255 
0256     grid->addWidget(pageButton, 0, 0);
0257     grid->addWidget(hruler, 0, 1);
0258     grid->addLayout(vboxlayout, 1, 0, 1, 2);
0259 
0260     pageButton->setMaximumSize(QSize(19, 22));
0261     pageButton->setMinimumSize(QSize(19, 22));
0262 
0263     if (!xml) {
0264         detail = new KReportDesignerSectionDetail(q);
0265         vboxlayout->insertWidget(0, detail);
0266     }
0267 
0268     connect(pageButton, &KReportPropertiesButton::released,
0269             q, &KReportDesigner::slotPageButton_Pressed);
0270     emit q->pagePropertyChanged(set);
0271 
0272     connect(&set, &KPropertySet::propertyChanged, q, &KReportDesigner::slotPropertyChanged);
0273 
0274     if (xml) {
0275         loadXml(*xml);
0276     }
0277     set.clearModifiedFlags();
0278     q->changeSet(&set);
0279 }
0280 
0281 void KReportDesigner::Private::loadXml(const QDomElement &data)
0282 {
0283     if (data.tagName() != QLatin1String("report:content")) {
0284         // arg we got an xml file but not one i know of
0285         kreportWarning() << "root element was not <report:content>";
0286     }
0287     //kreportDebug() << data.text();
0288 
0289     QDomNodeList nlist = data.childNodes();
0290     QDomNode it;
0291 
0292     for (int i = 0; i < nlist.count(); ++i) {
0293         it = nlist.item(i);
0294         // at this level all the children we get should be Elements
0295         if (it.isElement()) {
0296             QString n = it.nodeName().toLower();
0297             //kreportDebug() << n;
0298             if (n == QLatin1String("report:title")) {
0299                 q->setReportTitle(it.firstChild().nodeValue());
0300 #ifdef KREPORT_SCRIPTING
0301             } else if (n == QLatin1String("report:script")) {
0302                 originalInterpreter = it.toElement().attribute(QLatin1String("report:script-interpreter"), QLatin1String("javascript"));
0303                 if (originalInterpreter.isEmpty()) {
0304                     originalInterpreter = QLatin1String("javascript");
0305                 }
0306                 originalScript = it.firstChild().nodeValue();
0307                 script->setValue(originalScript);
0308 
0309                 if (originalInterpreter != QLatin1String("javascript") && originalInterpreter != QLatin1String("qtscript")) {
0310                     QString msg = tr("This report contains scripts of type \"%1\". "
0311                                      "Only scripts written in JavaScript language are "
0312                                      "supported. To prevent losing the scripts, their type "
0313                                      "and content will not be changed unless you change these scripts."
0314                                      ).arg(originalInterpreter);
0315                     QMessageBox::warning(q, tr("Unsupported Script Type"), msg);
0316                 }
0317 #endif
0318             } else if (n == QLatin1String("report:grid")) {
0319                 showGrid->setValue(it.toElement().attribute(QLatin1String("report:grid-visible"), QString::number(1)).toInt() != 0);
0320                 gridSnap->setValue(it.toElement().attribute(QLatin1String("report:grid-snap"), QString::number(1)).toInt() != 0);
0321                 gridDivisions->setValue(it.toElement().attribute(QLatin1String("report:grid-divisions"), QString::number(4)).toInt());
0322                 unit->setValue(it.toElement().attribute(QLatin1String("report:page-unit"), DEFAULT_UNIT_STRING));
0323                 updateCurrentUnit();
0324             }
0325 
0326             //! @todo Load page options
0327             else if (n == QLatin1String("report:page-style")) {
0328                 QString pagetype = it.firstChild().nodeValue();
0329 
0330                 if (pagetype == QLatin1String("predefined")) {
0331                     pageSize->setValue(it.toElement().attribute(QLatin1String("report:page-size"), QLatin1String("A4")));
0332                 } else if (pagetype == QLatin1String("custom")) {
0333                     pageSize->setValue(QLatin1String("Custom"));
0334                     customPageSize->setValue(QSizeF(KReportUnit::parseValue(it.toElement().attribute(QLatin1String("report:custom-page-width"), QLatin1String(""))),
0335                         KReportUnit::parseValue(it.toElement().attribute(QLatin1String("report:custom-page-height"), QLatin1String("")))));
0336                 } else if (pagetype == QLatin1String("label")) {
0337                     //! @todo
0338                 }
0339 
0340                 rightMargin->setValue(currentUnit.convertFromPoint(
0341                     KReportUnit::parseValue(it.toElement().attribute(
0342                         QLatin1String("fo:margin-right"), DEFAULT_PAGE_MARGIN_STRING))));
0343                 leftMargin->setValue(currentUnit.convertFromPoint(
0344                     KReportUnit::parseValue(it.toElement().attribute(
0345                         QLatin1String("fo:margin-left"), DEFAULT_PAGE_MARGIN_STRING))));
0346                 topMargin->setValue(currentUnit.convertFromPoint(
0347                     KReportUnit::parseValue(it.toElement().attribute(
0348                         QLatin1String("fo:margin-top"), DEFAULT_PAGE_MARGIN_STRING))));
0349                 bottomMargin->setValue(currentUnit.convertFromPoint(
0350                     KReportUnit::parseValue(it.toElement().attribute(
0351                         QLatin1String("fo:margin-bottom"), DEFAULT_PAGE_MARGIN_STRING))));
0352                 orientation->setValue(
0353                     it.toElement().attribute(QLatin1String("report:print-orientation"),
0354                                              QLatin1String("portrait")));
0355             } else if (n == QLatin1String("report:body")) {
0356                 QDomNodeList sectionlist = it.childNodes();
0357                 QDomNode sec;
0358 
0359                 for (int s = 0; s < sectionlist.count(); ++s) {
0360                     sec = sectionlist.item(s);
0361                     if (sec.isElement()) {
0362                         QString sn = sec.nodeName().toLower();
0363                         //kreportDebug() << sn;
0364                         if (sn == QLatin1String("report:section")) {
0365                             const QString sectiontype = KReportUtils::readSectionTypeNameAttribute(sec.toElement());
0366                             if (q->section(KReportSectionData::sectionTypeFromString(sectiontype)) == nullptr) {
0367                                 q->insertSection(KReportSectionData::sectionTypeFromString(sectiontype));
0368                                 q->section(KReportSectionData::sectionTypeFromString(sectiontype))->initFromXML(sec);
0369                             }
0370                         } else if (sn == QLatin1String("report:detail")) {
0371                             KReportDesignerSectionDetail * rsd = new KReportDesignerSectionDetail(q);
0372                             rsd->initFromXML(&sec);
0373                             q->setDetail(rsd);
0374                         }
0375                     } else {
0376                         kreportWarning() << "Encountered an unknown Element: "  << n;
0377                     }
0378                 }
0379             }
0380         } else {
0381             kreportWarning() << "Encountered a child node of root that is not an Element";
0382         }
0383     }
0384     updateScripts();
0385     emit q->reportDataChanged();
0386     q->slotPropertyChanged(set, *unit); // set unit for all items
0387     q->setModified(false);
0388 }
0389 
0390 #ifdef KREPORT_SCRIPTING
0391 void KReportDesigner::Private::updateScripts()
0392 {
0393     if (scriptSource) {
0394         QStringList sl = scriptSource->scriptList();
0395         sl.prepend(QString()); // prepend "none"
0396         script->setListData(sl, sl);
0397     }
0398 }
0399 #endif
0400 
0401 // ----
0402 
0403 KReportDesigner::KReportDesigner(QWidget * parent)
0404         : QWidget(parent), d(new Private(this))
0405 {
0406     d->init(nullptr);
0407 }
0408 
0409 KReportDesigner::KReportDesigner(QWidget *parent, const QDomElement &data)
0410     : QWidget(parent), d(new Private(this))
0411 {
0412     d->init(&data);
0413 }
0414 
0415 KReportDesigner::~KReportDesigner()
0416 {
0417     delete d;
0418 }
0419 
0420 ///The saving code
0421 QDomElement KReportDesigner::document() const
0422 {
0423     QDomDocument doc;
0424     QString saveInterpreter;
0425 
0426     QDomElement content = doc.createElement(QLatin1String("report:content"));
0427     content.setAttribute(QLatin1String("xmlns:report"), QLatin1String(ns));
0428     content.setAttribute(QLatin1String("xmlns:fo"), QLatin1String("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"));
0429     content.setAttribute(QLatin1String("xmlns:svg"), QLatin1String("urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"));
0430 
0431     doc.appendChild(content);
0432 
0433     //title
0434     content.appendChild(propertyToElement(&doc, d->title));
0435 
0436 #ifdef KREPORT_SCRIPTING
0437     if (d->originalInterpreter.isEmpty()) {
0438         d->originalInterpreter = QLatin1String("javascript");
0439     }
0440     saveInterpreter = d->originalInterpreter;
0441 
0442     if (!d->script->value().toString().isEmpty()) {
0443         if (d->script->value().toString() != d->originalScript || d->originalInterpreter == QLatin1String("qtscript") || d->originalInterpreter.isEmpty() ) {
0444             //The script has changed so force interpreter to 'javascript'.  Also set if was using qtscript
0445             saveInterpreter = QLatin1String("javascript");
0446         }
0447     }
0448 
0449     QDomElement scr = propertyToElement(&doc, d->script);
0450     scr.setAttribute(QLatin1String("report:script-interpreter"), saveInterpreter);
0451     content.appendChild(scr);
0452 #endif
0453 
0454     QDomElement grd = doc.createElement(QLatin1String("report:grid"));
0455     KReportUtils::addPropertyAsAttribute(&grd, d->showGrid);
0456     KReportUtils::addPropertyAsAttribute(&grd, d->gridDivisions);
0457     KReportUtils::addPropertyAsAttribute(&grd, d->gridSnap);
0458     KReportUtils::addPropertyAsAttribute(&grd, d->unit);
0459     content.appendChild(grd);
0460 
0461     // pageOptions
0462     // -- size
0463     QDomElement pagestyle = doc.createElement(QLatin1String("report:page-style"));
0464 
0465     if (d->pageSize->value().toString() == QLatin1String("Custom")) {
0466         pagestyle.appendChild(doc.createTextNode(QLatin1String("custom")));
0467 
0468         KReportUtils::setAttribute(
0469             &pagestyle, QLatin1String("report:custom-page-width"),
0470             d->currentUnit.convertToPoint(d->customPageSize->value().toSizeF().width()));
0471         KReportUtils::setAttribute(
0472             &pagestyle, QLatin1String("report:custom-page-height"),
0473             d->currentUnit.convertToPoint(d->customPageSize->value().toSizeF().height()));
0474     } else if (d->pageSize->value().toString() == QLatin1String("Label")) {
0475         pagestyle.appendChild(doc.createTextNode(QLatin1String("label")));
0476         pagestyle.setAttribute(QLatin1String("report:page-label-type"), d->labelType->value().toString());
0477     } else {
0478         pagestyle.appendChild(doc.createTextNode(QLatin1String("predefined")));
0479         KReportUtils::addPropertyAsAttribute(&pagestyle, d->pageSize);
0480         //pagestyle.setAttribute("report:page-size", d->pageSize->value().toString());
0481     }
0482 
0483     // -- orientation
0484     KReportUtils::addPropertyAsAttribute(&pagestyle, d->orientation);
0485 
0486     // -- margins: save as points, and not localized
0487     KReportUtils::setAttribute(
0488         &pagestyle, QLatin1String("fo:margin-top"),
0489         d->currentUnit.convertToPoint(d->topMargin->value().toDouble()));
0490     KReportUtils::setAttribute(
0491         &pagestyle, QLatin1String("fo:margin-bottom"),
0492         d->currentUnit.convertToPoint(d->bottomMargin->value().toDouble()));
0493     KReportUtils::setAttribute(
0494         &pagestyle, QLatin1String("fo:margin-right"),
0495         d->currentUnit.convertToPoint(d->rightMargin->value().toDouble()));
0496     KReportUtils::setAttribute(
0497         &pagestyle, QLatin1String("fo:margin-left"),
0498         d->currentUnit.convertToPoint(d->leftMargin->value().toDouble()));
0499 
0500     content.appendChild(pagestyle);
0501 
0502     QDomElement body = doc.createElement(QLatin1String("report:body"));
0503     QDomElement domsection;
0504 
0505     for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
0506          i <= static_cast<int>(KReportSectionData::Type::PageFooterAny); ++i)
0507     {
0508         KReportDesignerSection *sec = section(static_cast<KReportSectionData::Type>(i));
0509         if (sec) {
0510             domsection = doc.createElement(QLatin1String("report:section"));
0511             domsection.setAttribute(
0512                 QLatin1String("report:section-type"),
0513                 KReportSectionData::sectionTypeString(static_cast<KReportSectionData::Type>(i)));
0514             sec->buildXML(&doc, &domsection);
0515             body.appendChild(domsection);
0516         }
0517     }
0518 
0519     QDomElement detail = doc.createElement(QLatin1String("report:detail"));
0520     d->detail->buildXML(&doc, &detail);
0521     body.appendChild(detail);
0522 
0523     content.appendChild(body);
0524     return content;
0525 }
0526 
0527 void KReportDesigner::slotSectionEditor()
0528 {
0529     KReportSectionEditor se(this);
0530     (void)se.exec();
0531 }
0532 
0533 void KReportDesigner::setDataSource(KReportDataSource* source)
0534 {
0535     if (d->dataSource == source) {
0536         return;
0537     }
0538     delete d->dataSource;
0539 
0540     d->dataSource = source;
0541     slotPageButton_Pressed();
0542     setModified(true);
0543     emit reportDataChanged();
0544 }
0545 
0546 #ifdef KREPORT_SCRIPTING
0547 void KReportDesigner::setScriptSource(KReportScriptSource* source)
0548 {
0549     d->scriptSource = source;
0550     d->updateScripts();
0551 }
0552 #endif
0553 
0554 KReportDesignerSection * KReportDesigner::section(KReportSectionData::Type type) const
0555 {
0556     KReportDesignerSection *sec;
0557     switch (type) {
0558     case KReportSectionData::Type::PageHeaderAny:
0559         sec = d->pageHeaderAny;
0560         break;
0561     case KReportSectionData::Type::PageHeaderEven:
0562         sec = d->pageHeaderEven;
0563         break;
0564     case KReportSectionData::Type::PageHeaderOdd:
0565         sec = d->pageHeaderOdd;
0566         break;
0567     case KReportSectionData::Type::PageHeaderFirst:
0568         sec = d->pageHeaderFirst;
0569         break;
0570     case KReportSectionData::Type::PageHeaderLast:
0571         sec = d->pageHeaderLast;
0572         break;
0573     case KReportSectionData::Type::PageFooterAny:
0574         sec = d->pageFooterAny;
0575         break;
0576     case KReportSectionData::Type::PageFooterEven:
0577         sec = d->pageFooterEven;
0578         break;
0579     case KReportSectionData::Type::PageFooterOdd:
0580         sec = d->pageFooterOdd;
0581         break;
0582     case KReportSectionData::Type::PageFooterFirst:
0583         sec = d->pageFooterFirst;
0584         break;
0585     case KReportSectionData::Type::PageFooterLast:
0586         sec = d->pageFooterLast;
0587         break;
0588     case KReportSectionData::Type::ReportHeader:
0589         sec = d->reportHeader;
0590         break;
0591     case KReportSectionData::Type::ReportFooter:
0592         sec = d->reportFooter;
0593         break;
0594     default:
0595         sec = nullptr;
0596     }
0597     return sec;
0598 }
0599 
0600 KReportDesignerSection* KReportDesigner::createSection()
0601 {
0602     return new KReportDesignerSection(this, d->zoomHandler);
0603 }
0604 
0605 void KReportDesigner::removeSection(KReportSectionData::Type type)
0606 {
0607     KReportDesignerSection* sec = section(type);
0608     if (sec) {
0609         delete sec;
0610 
0611         switch (type) {
0612         case KReportSectionData::Type::PageHeaderAny:
0613             d->pageHeaderAny = nullptr;
0614             break;
0615         case KReportSectionData::Type::PageHeaderEven:
0616             sec = d->pageHeaderEven = nullptr;
0617             break;
0618         case KReportSectionData::Type::PageHeaderOdd:
0619             d->pageHeaderOdd = nullptr;
0620             break;
0621         case KReportSectionData::Type::PageHeaderFirst:
0622             d->pageHeaderFirst = nullptr;
0623             break;
0624         case KReportSectionData::Type::PageHeaderLast:
0625             d->pageHeaderLast = nullptr;
0626             break;
0627         case KReportSectionData::Type::PageFooterAny:
0628             d->pageFooterAny = nullptr;
0629             break;
0630         case KReportSectionData::Type::PageFooterEven:
0631             d->pageFooterEven = nullptr;
0632             break;
0633         case KReportSectionData::Type::PageFooterOdd:
0634             d->pageFooterOdd = nullptr;
0635             break;
0636         case KReportSectionData::Type::PageFooterFirst:
0637             d->pageFooterFirst = nullptr;
0638             break;
0639         case KReportSectionData::Type::PageFooterLast:
0640             d->pageFooterLast = nullptr;
0641             break;
0642         case KReportSectionData::Type::ReportHeader:
0643             d->reportHeader = nullptr;
0644             break;
0645         case KReportSectionData::Type::ReportFooter:
0646             d->reportFooter = nullptr;
0647             break;
0648         default:
0649             sec = nullptr;
0650         }
0651 
0652         setModified(true);
0653         adjustSize();
0654     }
0655 }
0656 
0657 void KReportDesigner::insertSection(KReportSectionData::Type type)
0658 {
0659     KReportDesignerSection* sec = section(type);
0660     if (!sec) {
0661         int idx = 0;
0662         for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
0663              i <= static_cast<int>(type); ++i)
0664         {
0665             if (section(static_cast<KReportSectionData::Type>(i)))
0666                 idx++;
0667         }
0668         if (type > KReportSectionData::Type::ReportHeader)
0669             idx++;
0670         //kreportDebug() << idx;
0671         KReportDesignerSection *rs = createSection();
0672         d->vboxlayout->insertWidget(idx, rs);
0673 
0674         switch (type) {
0675         case KReportSectionData::Type::PageHeaderAny:
0676             rs->setTitle(tr("Page Header (Any)"));
0677             d->pageHeaderAny = rs;
0678             break;
0679         case KReportSectionData::Type::PageHeaderEven:
0680             rs->setTitle(tr("Page Header (Even)"));
0681             d->pageHeaderEven = rs;
0682             break;
0683         case KReportSectionData::Type::PageHeaderOdd:
0684             rs->setTitle(tr("Page Header (Odd)"));
0685             d->pageHeaderOdd = rs;
0686             break;
0687         case KReportSectionData::Type::PageHeaderFirst:
0688             rs->setTitle(tr("Page Header (First)"));
0689             d->pageHeaderFirst = rs;
0690             break;
0691         case KReportSectionData::Type::PageHeaderLast:
0692             rs->setTitle(tr("Page Header (Last)"));
0693             d->pageHeaderLast = rs;
0694             break;
0695         case KReportSectionData::Type::PageFooterAny:
0696             rs->setTitle(tr("Page Footer (Any)"));
0697             d->pageFooterAny = rs;
0698             break;
0699         case KReportSectionData::Type::PageFooterEven:
0700             rs->setTitle(tr("Page Footer (Even)"));
0701             d->pageFooterEven = rs;
0702             break;
0703         case KReportSectionData::Type::PageFooterOdd:
0704             rs->setTitle(tr("Page Footer (Odd)"));
0705             d->pageFooterOdd = rs;
0706             break;
0707         case KReportSectionData::Type::PageFooterFirst:
0708             rs->setTitle(tr("Page Footer (First)"));
0709             d->pageFooterFirst = rs;
0710             break;
0711         case KReportSectionData::Type::PageFooterLast:
0712             rs->setTitle(tr("Page Footer (Last)"));
0713             d->pageFooterLast = rs;
0714             break;
0715         case KReportSectionData::Type::ReportHeader:
0716             rs->setTitle(tr("Report Header"));
0717             d->reportHeader = rs;
0718             break;
0719         case KReportSectionData::Type::ReportFooter:
0720             rs->setTitle(tr("Report Footer"));
0721             d->reportFooter = rs;
0722             break;
0723             //These sections cannot be inserted this way
0724         case KReportSectionData::Type::None:
0725         case KReportSectionData::Type::GroupHeader:
0726         case KReportSectionData::Type::GroupFooter:
0727         case KReportSectionData::Type::Detail:
0728             break;
0729         }
0730 
0731         rs->show();
0732         setModified(true);
0733         adjustSize();
0734         emit pagePropertyChanged(d->set);
0735     }
0736 }
0737 
0738 void KReportDesigner::setReportTitle(const QString & str)
0739 {
0740     if (reportTitle() != str) {
0741         d->title->setValue(str);
0742         setModified(true);
0743     }
0744 }
0745 
0746 KPropertySet* KReportDesigner::propertySet() const
0747 {
0748     return &d->set;
0749 }
0750 
0751 KPropertySet* KReportDesigner::selectedItemPropertySet() const
0752 {
0753     return d->itemSet;
0754 }
0755 
0756 KReportDataSource *KReportDesigner::reportDataSource() const
0757 {
0758     return d->dataSource;
0759 }
0760 
0761 KReportDesignerSectionDetail * KReportDesigner::detailSection() const
0762 {
0763     return d->detail;
0764 }
0765 
0766 QString KReportDesigner::reportTitle() const
0767 {
0768     return d->title->value().toString();
0769 }
0770 
0771 bool KReportDesigner::isModified() const
0772 {
0773     return d->modified;
0774 }
0775 
0776 void KReportDesigner::setModified(bool modified)
0777 {
0778     d->modified = modified;
0779 
0780     if (d->modified) {
0781         emit dirty();
0782     }
0783 }
0784 
0785 QStringList KReportDesigner::fieldNames() const
0786 {
0787     QStringList qs;
0788     qs << QString();
0789     if (d->dataSource)
0790         qs << d->dataSource->fieldNames();
0791 
0792     return qs;
0793 }
0794 
0795 QStringList KReportDesigner::fieldKeys() const
0796 {
0797     QStringList qs;
0798     qs << QString();
0799     if (d->dataSource)
0800         qs << d->dataSource->fieldKeys();
0801 
0802     return qs;
0803 }
0804 
0805 void KReportDesigner::createProperties()
0806 {
0807     KReportDesigner::addMetaProperties(&d->set,
0808         tr("Report", "Main report element"), QLatin1String("kreport-report-element"));
0809 
0810     connect(&d->set, SIGNAL(propertyChanged(KPropertySet&,KProperty&)),
0811             this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&)));
0812 
0813     d->title = new KProperty("title", QLatin1String("Report"), tr("Title"), tr("Report Title"));
0814 
0815     KPropertyListData *listData = new KPropertyListData(KReportPageSize::pageFormatKeys(),
0816                                                         KReportPageSize::pageFormatNames());
0817     QVariant defaultKey = KReportPageSize::pageSizeKey(KReportPageSize::defaultSize());
0818     d->pageSize = new KProperty("page-size", listData, defaultKey, tr("Page Size"));
0819 
0820     d->customPageSize = new KProperty("custom-page-size", DEFAULT_CUSTOM_PAGE_SIZE,
0821         tr("Custom Page Size"), tr("Custom Page Size"), KProperty::SizeF);
0822     d->customPageSize->setOption("suffix", d->currentUnit.symbol());
0823 
0824     listData = new KPropertyListData({ QLatin1String("portrait"), QLatin1String("landscape") },
0825                                      QVariantList{ tr("Portrait"), tr("Landscape") });
0826     d->orientation = new KProperty("print-orientation", listData, QLatin1String("portrait"),
0827                                    tr("Page Orientation"));
0828 
0829     QList<KReportUnit::Type> types(KReportUnit::allTypes());
0830     types.removeOne(KReportUnit::Type::Pixel);
0831     listData = new KPropertyListData(KReportUnit::symbols(types), KReportUnit::descriptions(types));
0832     d->unit = new KProperty("page-unit", listData, DEFAULT_UNIT_STRING, tr("Page Unit"));
0833     d->showGrid = new KProperty("grid-visible", true, tr("Show Grid"));
0834     d->gridSnap = new KProperty("grid-snap", true, tr("Snap to Grid"));
0835     d->gridDivisions = new KProperty("grid-divisions", 4, tr("Grid Divisions"));
0836     d->gridDivisions->setOption("min", 1);
0837     d->gridDivisions->setOption("max", 10);
0838 
0839 
0840     d->leftMargin = new KProperty("margin-left", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
0841         tr("Left Margin"), tr("Left Margin"), KProperty::Double);
0842     d->rightMargin = new KProperty("margin-right", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
0843         tr("Right Margin"), tr("Right Margin"), KProperty::Double);
0844     d->topMargin = new KProperty("margin-top", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
0845         tr("Top Margin"), tr("Top Margin"), KProperty::Double);
0846     d->bottomMargin = new KProperty("margin-bottom", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
0847         tr("Bottom Margin"), tr("Bottom Margin"), KProperty::Double);
0848     d->leftMargin->setOption("suffix", d->currentUnit.symbol());
0849     d->rightMargin->setOption("suffix", d->currentUnit.symbol());
0850     d->topMargin->setOption("suffix", d->currentUnit.symbol());
0851     d->bottomMargin->setOption("suffix", d->currentUnit.symbol());
0852 
0853     d->set.addProperty(d->title);
0854     d->set.addProperty(d->pageSize);
0855     d->set.addProperty(d->customPageSize);
0856     d->set.addProperty(d->orientation);
0857     d->set.addProperty(d->unit);
0858     d->set.addProperty(d->gridSnap);
0859     d->set.addProperty(d->showGrid);
0860     d->set.addProperty(d->gridDivisions);
0861     d->set.addProperty(d->leftMargin);
0862     d->set.addProperty(d->rightMargin);
0863     d->set.addProperty(d->topMargin);
0864     d->set.addProperty(d->bottomMargin);
0865 
0866     recalculateMaxMargins();
0867 
0868 #ifdef KREPORT_SCRIPTING
0869     d->script = new KProperty("script", new KPropertyListData, QVariant(), tr("Object Script"));
0870     d->set.addProperty(d->script);
0871 #endif
0872 }
0873 
0874 /**
0875 @brief Handle property changes
0876 */
0877 void KReportDesigner::slotPropertyChanged(KPropertySet &s, KProperty &p)
0878 {
0879     const QSignalBlocker blocker(s);
0880     setModified(true);
0881     QByteArray propertyName = p.name();
0882 
0883     if (propertyName == "page-unit") {
0884         const KReportUnit oldUnit = d->currentUnit;
0885         d->updateCurrentUnit();
0886         d->hruler->setUnit(pageUnit());
0887 
0888         // convert values
0889         d->leftMargin->setValue(KReportUnit::convertFromUnitToUnit(
0890                                     d->leftMargin->value().toDouble(), oldUnit, d->currentUnit),
0891                                 KProperty::ValueOption::IgnoreOld);
0892 
0893         d->rightMargin->setValue(KReportUnit::convertFromUnitToUnit(
0894                                      d->rightMargin->value().toDouble(), oldUnit, d->currentUnit),
0895                                  KProperty::ValueOption::IgnoreOld);
0896 
0897         d->topMargin->setValue(KReportUnit::convertFromUnitToUnit(d->topMargin->value().toDouble(),
0898                                                                   oldUnit, d->currentUnit),
0899                                KProperty::ValueOption::IgnoreOld);
0900 
0901         d->bottomMargin->setValue(KReportUnit::convertFromUnitToUnit(
0902                                       d->bottomMargin->value().toDouble(), oldUnit, d->currentUnit),
0903                                   KProperty::ValueOption::IgnoreOld);
0904 
0905         d->customPageSize->setValue(
0906             KReportUnit::convertFromUnitToUnit(d->customPageSize->value().toSizeF(), oldUnit,
0907                                                d->currentUnit),
0908             KProperty::ValueOption::IgnoreOld);
0909 
0910         d->leftMargin->setOption("suffix", d->currentUnit.symbol());
0911         d->rightMargin->setOption("suffix", d->currentUnit.symbol());
0912         d->topMargin->setOption("suffix", d->currentUnit.symbol());
0913         d->bottomMargin->setOption("suffix", d->currentUnit.symbol());
0914         d->customPageSize->setOption("suffix", d->currentUnit.symbol());
0915     } else if (propertyName.startsWith("margin-") || propertyName == "page-size" || propertyName == "custom-page-size") {
0916         recalculateMaxMargins();
0917     }
0918     emit pagePropertyChanged(s);
0919 
0920 }
0921 
0922 void KReportDesigner::slotPageButton_Pressed()
0923 {
0924 #ifdef KREPORT_SCRIPTING
0925     d->updateScripts();
0926     changeSet(&d->set);
0927 #endif
0928 }
0929 
0930 QSize KReportDesigner::sizeHint() const
0931 {
0932     int w = 0;
0933     int h = 0;
0934 
0935     if (d->pageFooterAny)
0936         h += d->pageFooterAny->sizeHint().height();
0937     if (d->pageFooterEven)
0938         h += d->pageFooterEven->sizeHint().height();
0939     if (d->pageFooterFirst)
0940         h += d->pageFooterFirst->sizeHint().height();
0941     if (d->pageFooterLast)
0942         h += d->pageFooterLast->sizeHint().height();
0943     if (d->pageFooterOdd)
0944         h += d->pageFooterOdd->sizeHint().height();
0945     if (d->pageHeaderAny)
0946         h += d->pageHeaderAny->sizeHint().height();
0947     if (d->pageHeaderEven)
0948         h += d->pageHeaderEven->sizeHint().height();
0949     if (d->pageHeaderFirst)
0950         h += d->pageHeaderFirst->sizeHint().height();
0951     if (d->pageHeaderLast)
0952         h += d->pageHeaderLast->sizeHint().height();
0953     if (d->pageHeaderOdd)
0954         h += d->pageHeaderOdd->sizeHint().height();
0955     if (d->reportHeader)
0956         h += d->reportHeader->sizeHint().height();
0957     if (d->reportFooter) {
0958         h += d->reportFooter->sizeHint().height();
0959 
0960     }
0961     if (d->detail) {
0962         h += d->detail->sizeHint().height();
0963         w += d->detail->sizeHint().width();
0964     }
0965 
0966     h += d->hruler->height();
0967 
0968     return QSize(w, h);
0969 }
0970 
0971 int KReportDesigner::pageWidthPx() const
0972 {
0973     QSize pageSizePx;
0974     int pageWidth;
0975 
0976     if (d->set.property("page-size").value().toString() == QLatin1String("Custom")) {
0977         KReportUnit unit = pageUnit();
0978 
0979         QSizeF customSize = d->currentUnit.convertToPoint(d->set.property("custom-page-size").value().toSizeF());
0980         QPageLayout layout(QPageSize(customSize, QPageSize::Point, QString(), QPageSize::ExactMatch), d->set.property("print-orientation").value().toString()
0981                     == QLatin1String("portrait") ? QPageLayout::Portrait : QPageLayout::Landscape, QMarginsF(0,0,0,0));
0982 
0983         pageSizePx = layout.fullRectPixels(KReportPrivate::dpiX()).size();
0984     } else {
0985         QPageLayout layout = QPageLayout(
0986             QPageSize(KReportPageSize::pageSize(d->set.property("page-size").value().toString())),
0987             d->set.property("print-orientation").value().toString()
0988                     == QLatin1String("portrait") ? QPageLayout::Portrait : QPageLayout::Landscape, QMarginsF(0,0,0,0));
0989         pageSizePx = layout.fullRectPixels(KReportPrivate::dpiX()).size();
0990     }
0991 
0992     pageWidth = pageSizePx.width();
0993 
0994     pageWidth = pageWidth - KReportUnit::convertFromUnitToUnit(d->set.property("margin-left").value().toDouble(), pageUnit(), KReportUnit(KReportUnit::Type::Inch)) * KReportPrivate::dpiX();
0995     pageWidth = pageWidth - KReportUnit::convertFromUnitToUnit(d->set.property("margin-right").value().toDouble(), pageUnit(), KReportUnit(KReportUnit::Type::Inch)) * KReportPrivate::dpiX();
0996 
0997     return pageWidth;
0998 }
0999 
1000 QSize KReportDesigner::pageSizePt() const
1001 {
1002     QSize pageSizePt;
1003 
1004     if (d->set.property("page-size").value().toString() == QLatin1String("Custom")) {
1005         KReportUnit unit = pageUnit();
1006 
1007         QSizeF customSize = d->currentUnit.convertToPoint(d->set.property("custom-page-size").value().toSizeF());
1008         QPageLayout layout(QPageSize(customSize, QPageSize::Point, QString(), QPageSize::ExactMatch), d->set.property("print-orientation").value().toString()
1009                     == QLatin1String("portrait") ? QPageLayout::Portrait : QPageLayout::Landscape, QMarginsF(0,0,0,0));
1010 
1011         pageSizePt = layout.fullRectPoints().size();
1012     } else {
1013         QPageLayout layout = QPageLayout(
1014             QPageSize(KReportPageSize::pageSize(d->set.property("page-size").value().toString())),
1015             d->set.property("print-orientation").value().toString()
1016                     == QLatin1String("portrait") ? QPageLayout::Portrait : QPageLayout::Landscape, QMarginsF(0,0,0,0));
1017         pageSizePt = layout.fullRectPoints().size();
1018     }
1019 
1020     return pageSizePt;
1021 }
1022 
1023 void KReportDesigner::resizeEvent(QResizeEvent * event)
1024 {
1025     Q_UNUSED(event);
1026     d->hruler->setRulerLength(pageWidthPx());
1027 }
1028 
1029 void KReportDesigner::setDetail(KReportDesignerSectionDetail *rsd)
1030 {
1031     if (!d->detail) {
1032         int idx = 0;
1033         if (d->pageHeaderFirst) idx++;
1034         if (d->pageHeaderOdd) idx++;
1035         if (d->pageHeaderEven) idx++;
1036         if (d->pageHeaderLast) idx++;
1037         if (d->pageHeaderAny) idx++;
1038         if (d->reportHeader) idx++;
1039         d->detail = rsd;
1040         d->vboxlayout->insertWidget(idx, d->detail);
1041     }
1042 }
1043 
1044 KReportUnit KReportDesigner::pageUnit() const
1045 {
1046     return d->currentUnit;
1047 }
1048 
1049 void KReportDesigner::setGridOptions(bool vis, int div)
1050 {
1051     d->showGrid->setValue(QVariant(vis));
1052     d->gridDivisions->setValue(div);
1053 }
1054 
1055 //
1056 // methods for the sectionMouse*Event()
1057 //
1058 void KReportDesigner::sectionContextMenuEvent(KReportDesignerSectionScene * s, QGraphicsSceneContextMenuEvent * e)
1059 {
1060     Q_UNUSED(s);
1061 
1062     QMenu pop;
1063 
1064     bool itemsSelected = selectionCount() > 0;
1065     if (itemsSelected) {
1066         //! @todo KF5 use KStandardAction
1067         QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-cut")), tr("Cut"), this);
1068         connect(a, SIGNAL(triggered()), this, SLOT(slotEditCut()));
1069         pop.addAction(a);
1070         //! @todo KF5 use KStandardAction
1071         a = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), tr("Copy"), this);
1072         connect(a, SIGNAL(triggered()), this, SLOT(slotEditCopy()));
1073         pop.addAction(a);
1074     }
1075     if (!d->sectionData.copy_list.isEmpty()) {
1076         QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-paste")), tr("Paste"), this);
1077         connect(a, SIGNAL(triggered()), this, SLOT(slotEditPaste()));
1078         pop.addAction(a);
1079     }
1080 
1081     if (itemsSelected) {
1082         pop.addSeparator();
1083         //! @todo KF5 use KStandard*
1084         //const KGuiItem del = KStandardGuiItem::del();
1085         //a->setToolTip(del.toolTip());
1086         //a->setShortcut(QKeySequence(QKeySequence::Delete));
1087         QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), tr("Delete"), this);
1088         connect(a, SIGNAL(triggered()), SLOT(slotEditDelete()));
1089         pop.addAction(a);
1090     }
1091     if (!pop.actions().isEmpty()) {
1092         pop.exec(e->screenPos());
1093     }
1094 }
1095 
1096 void KReportDesigner::sectionMousePressEvent(KReportDesignerSectionView * v, QMouseEvent * e)
1097 {
1098     Q_UNUSED(v);
1099     d->pressX = e->pos().x();
1100     d->pressY = e->pos().y();
1101 }
1102 
1103 void KReportDesigner::sectionMouseReleaseEvent(KReportDesignerSectionView * v, QMouseEvent * e)
1104 {
1105     e->accept();
1106 
1107     d->releaseX = e->pos().x();
1108     d->releaseY = e->pos().y();
1109 
1110     if (e->button() == Qt::LeftButton) {
1111         QPointF pos(d->pressX, d->pressY);
1112         QPointF end(d->releaseX, d->releaseY);
1113         if (d->releaseY >= v->scene()->height()) {
1114             d->releaseY = v->scene()->height();
1115             end.setY(v->scene()->height());
1116         }
1117 
1118         if (d->releaseX >= v->scene()->width()) {
1119             d->releaseX = v->scene()->width();
1120             end.setX(v->scene()->width());
1121         }
1122 
1123         if (d->sectionData.mouseAction == ReportWriterSectionData::MouseAction::Insert) {
1124             QGraphicsItem * item = nullptr;
1125             QString classString;
1126             QString iconName;
1127             if (d->sectionData.itemToInsert == QLatin1String("org.kde.kreport.line")) {
1128                 item = new KReportDesignerItemLine(v->designer(), v->scene(), pos, end);
1129                 classString = tr("Line", "Report line element");
1130                 iconName = QLatin1String("kreport-line-element");
1131             }
1132             else {
1133                 KReportPluginManager* pluginManager = KReportPluginManager::self();
1134                 KReportPluginInterface *plug = pluginManager->plugin(d->sectionData.itemToInsert);
1135                 if (plug) {
1136                     QObject *obj = plug->createDesignerInstance(v->designer(), v->scene(), pos);
1137                     if (obj) {
1138                         item = dynamic_cast<QGraphicsItem*>(obj);
1139                         classString = plug->metaData()->name();
1140                         iconName = plug->metaData()->iconName();
1141                     }
1142                 }
1143                 else {
1144                     kreportWarning() << "attempted to insert an unknown item";
1145                 }
1146             }
1147             if (item) {
1148                 item->setVisible(true);
1149                 item->setSelected(true);
1150                 KReportItemBase* baseReportItem = dynamic_cast<KReportItemBase*>(item);
1151                 if (baseReportItem) {
1152                     KPropertySet *set = baseReportItem->propertySet();
1153                     KReportDesigner::addMetaProperties(set, classString, iconName);
1154                     set->clearModifiedFlags();
1155                     changeSet(set);
1156                     if (v && v->designer()) {
1157                         v->designer()->setModified(true);
1158                     }
1159                     emit itemInserted(d->sectionData.itemToInsert);
1160                 }
1161             }
1162 
1163             d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::None;
1164             d->sectionData.itemToInsert.clear();
1165             unsetSectionCursor();
1166         }
1167     }
1168 }
1169 
1170 unsigned int KReportDesigner::selectionCount() const
1171 {
1172     if (activeScene())
1173         return activeScene()->selectedItems().count();
1174     else
1175         return 0;
1176 }
1177 
1178 void KReportDesigner::changeSet(KPropertySet *set)
1179 {
1180     //Set the checked state of the report properties button
1181     if (set == &d->set)
1182         d->pageButton->setCheckState(Qt::Checked);
1183     else
1184         d->pageButton->setCheckState(Qt::Unchecked);
1185 
1186     if (d->itemSet != set) {
1187         d->itemSet = set;
1188         emit propertySetChanged();
1189     }
1190 }
1191 
1192 //
1193 // Actions
1194 //
1195 
1196 void KReportDesigner::slotItem(const QString &entity)
1197 {
1198     //kreportDebug() << entity;
1199     d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::Insert;
1200     d->sectionData.itemToInsert = entity;
1201     setSectionCursor(QCursor(Qt::CrossCursor));
1202 }
1203 
1204 void KReportDesigner::slotEditDelete()
1205 {
1206     QGraphicsItem * item = nullptr;
1207     bool modified = false;
1208     while (selectionCount() > 0) {
1209         item = activeScene()->selectedItems().value(0);
1210         if (item) {
1211             QGraphicsScene * scene = item->scene();
1212             delete item;
1213             scene->update();
1214             d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::None;
1215             modified = true;
1216         }
1217     }
1218     activeScene()->selectedItems().clear();
1219 
1220     /*! @todo temporary: clears cut and copy lists to make sure we do not crash
1221      if weve deleted something in the list
1222      should really check if an item is in the list first
1223      and remove it. */
1224     d->sectionData.cut_list.clear();
1225     d->sectionData.copy_list.clear();
1226     if (modified) {
1227         setModified(true);
1228     }
1229 }
1230 
1231 void KReportDesigner::slotEditCut()
1232 {
1233     if (selectionCount() > 0) {
1234         //First delete any items that are curerntly in the list
1235         //so as not to leak memory
1236         qDeleteAll(d->sectionData.cut_list);
1237         d->sectionData.cut_list.clear();
1238 
1239         QGraphicsItem * item = activeScene()->selectedItems().first();
1240         bool modified = false;
1241         if (item) {
1242             d->sectionData.copy_list.clear();
1243             foreach(QGraphicsItem *item, activeScene()->selectedItems()) {
1244                 d->sectionData.cut_list.append(dynamic_cast<KReportDesignerItemBase*>(item));
1245                 d->sectionData.copy_list.append(dynamic_cast<KReportDesignerItemBase*>(item));
1246             }
1247             foreach(QGraphicsItem *item, activeScene()->selectedItems()) {
1248                 activeScene()->removeItem(item);
1249                 activeScene()->update();
1250                 modified = true;
1251             }
1252             d->sectionData.selected_x_offset = 10;
1253             d->sectionData.selected_y_offset = 10;
1254         }
1255         if (modified) {
1256             setModified(true);
1257         }
1258     }
1259 }
1260 
1261 void KReportDesigner::slotEditCopy()
1262 {
1263     if (selectionCount() < 1)
1264         return;
1265 
1266     QGraphicsItem * item = activeScene()->selectedItems().first();
1267     if (item) {
1268         d->sectionData.copy_list.clear();
1269         foreach(QGraphicsItem *item, activeScene()->selectedItems()) {
1270             d->sectionData.copy_list.append(dynamic_cast<KReportDesignerItemBase*>(item));
1271         }
1272         d->sectionData.selected_x_offset = 10;
1273         d->sectionData.selected_y_offset = 10;
1274     }
1275 }
1276 
1277 void KReportDesigner::slotEditPaste()
1278 {
1279     // call the editPaste function passing it a reportsection
1280     slotEditPaste(activeScene());
1281 }
1282 
1283 void KReportDesigner::slotEditPaste(QGraphicsScene * canvas)
1284 {
1285 
1286     // paste a new item of the copy we have in the specified location
1287     if (!d->sectionData.copy_list.isEmpty()) {
1288         QList<QGraphicsItem*> activeItems = canvas->selectedItems();
1289         QGraphicsItem *activeItem = nullptr;
1290         if (activeItems.count() == 1) {
1291             activeItem = activeItems.first();
1292         }
1293         canvas->clearSelection();
1294         d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::None;
1295 
1296         //! @todo this code sucks :)
1297         //! The setPos calls only work AFTER the name has been set ?!?!?
1298 
1299         foreach(KReportDesignerItemBase *item, d->sectionData.copy_list) {
1300             KReportItemBase *obj = dynamic_cast<KReportItemBase*>(item);
1301             const QString type = obj ? obj->typeName() : QLatin1String("object");
1302             //kreportDebug() << type;
1303             KReportDesignerItemBase *ent = item->clone();
1304             KReportItemBase *new_obj = dynamic_cast<KReportItemBase*>(ent);
1305             if (new_obj) {
1306                 new_obj->setEntityName(suggestEntityName(type));
1307                 if (activeItem) {
1308                     new_obj->setPosition(KReportItemBase::positionFromScene(QPointF(activeItem->x() + 10, activeItem->y() + 10)));
1309                 } else {
1310                     new_obj->setPosition(KReportItemBase::positionFromScene(QPointF(0, 0)));
1311                 }
1312                 new_obj->propertySet()->clearModifiedFlags();
1313                 changeSet(new_obj->propertySet());
1314             }
1315             QGraphicsItem *pasted_ent = dynamic_cast<QGraphicsItem*>(ent);
1316             if (pasted_ent) {
1317                 pasted_ent->setSelected(true);
1318                 canvas->addItem(pasted_ent);
1319                 pasted_ent->show();
1320                 d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::Grab;
1321                 setModified(true);
1322             }
1323         }
1324     }
1325 }
1326 void KReportDesigner::slotRaiseSelected()
1327 {
1328     dynamic_cast<KReportDesignerSectionScene*>(activeScene())->raiseSelected();
1329 }
1330 
1331 void KReportDesigner::slotLowerSelected()
1332 {
1333     dynamic_cast<KReportDesignerSectionScene*>(activeScene())->lowerSelected();
1334 }
1335 
1336 QGraphicsScene* KReportDesigner::activeScene() const
1337 {
1338     return d->activeScene;
1339 }
1340 
1341 void KReportDesigner::setActiveScene(QGraphicsScene* a)
1342 {
1343     if (d->activeScene && d->activeScene != a)
1344         d->activeScene->clearSelection();
1345     d->activeScene = a;
1346 
1347     //Trigger an update so that the last scene redraws its title;
1348     update();
1349 }
1350 
1351 QString KReportDesigner::suggestEntityName(const QString &name) const
1352 {
1353     KReportDesignerSection *sec;
1354     int itemCount = 0;
1355     // Count items in the main sections
1356     for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
1357          i <= static_cast<int>(KReportSectionData::Type::PageFooterAny); i++)
1358     {
1359         sec = section(static_cast<KReportSectionData::Type>(i));
1360         if (sec) {
1361             const QGraphicsItemList l = sec->items();
1362             itemCount += l.count();
1363         }
1364     }
1365 
1366     if (d->detail) {
1367         //Count items in the group headers/footers
1368         for (int i = 0; i < d->detail->groupSectionCount(); i++) {
1369             sec = d->detail->groupSection(i)->groupHeader();
1370             if (sec) {
1371                 const QGraphicsItemList l = sec->items();
1372                 itemCount += l.count();
1373             }
1374             sec = d->detail->groupSection(i)->groupFooter();
1375             if (sec) {
1376                 const QGraphicsItemList l = sec->items();
1377                 itemCount += l.count();
1378             }
1379         }
1380 
1381         sec = d->detail->detailSection();
1382         if (sec) {
1383             const QGraphicsItemList l = sec->items();
1384             itemCount += l.count();
1385         }
1386     }
1387 
1388     while (!isEntityNameUnique(name + QString::number(itemCount))) {
1389         itemCount++;
1390     }
1391     return name + QString::number(itemCount);
1392 }
1393 
1394 bool KReportDesigner::isEntityNameUnique(const QString &name, KReportItemBase* ignore) const
1395 {
1396     KReportDesignerSection *sec;
1397     bool unique = true;
1398 
1399     // Check items in the main sections
1400     for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
1401          i <= static_cast<int>(KReportSectionData::Type::PageFooterAny); i++)
1402     {
1403         sec = section(static_cast<KReportSectionData::Type>(i));
1404         if (sec) {
1405             const QGraphicsItemList l = sec->items();
1406             for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) {
1407                 KReportItemBase* itm = dynamic_cast<KReportItemBase*>(*it);
1408                 if (itm && itm->entityName() == name  && itm != ignore) {
1409                     unique = false;
1410                     break;
1411                 }
1412             }
1413             if (!unique) break;
1414         }
1415     }
1416 
1417     //Count items in the group headers/footers
1418     if (unique && d->detail) {
1419         for (int i = 0; i < d->detail->groupSectionCount(); ++i) {
1420             sec = d->detail->groupSection(i)->groupHeader();
1421             if (sec) {
1422                 const QGraphicsItemList l = sec->items();
1423                 for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) {
1424                     KReportItemBase* itm = dynamic_cast<KReportItemBase*>(*it);
1425                     if (itm && itm->entityName() == name  && itm != ignore) {
1426                         unique = false;
1427                         break;
1428                     }
1429                 }
1430 
1431             }
1432             sec = d->detail->groupSection(i)->groupFooter();
1433             if (unique && sec) {
1434                 const QGraphicsItemList l = sec->items();
1435                 for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) {
1436                     KReportItemBase* itm = dynamic_cast<KReportItemBase*>(*it);
1437                     if (itm && itm->entityName() == name  && itm != ignore) {
1438                         unique = false;
1439                         break;
1440                     }
1441                 }
1442             }
1443         }
1444     }
1445     if (unique && d->detail) {
1446         sec = d->detail->detailSection();
1447         if (sec) {
1448             const QGraphicsItemList l = sec->items();
1449             for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) {
1450                 KReportItemBase* itm = dynamic_cast<KReportItemBase*>(*it);
1451                 if (itm && itm->entityName() == name  && itm != ignore) {
1452                     unique = false;
1453                     break;
1454                 }
1455             }
1456         }
1457     }
1458 
1459     return unique;
1460 }
1461 
1462 static bool actionPriortyLessThan(QAction* act1, QAction* act2)
1463 {
1464     if (act1->data().toInt() > 0 && act2->data().toInt() > 0) {
1465         return act1->data().toInt() < act2->data().toInt();
1466     }
1467     return false;
1468 }
1469 
1470 QList<QAction*> KReportDesigner::itemActions(QActionGroup* group)
1471 {
1472     KReportPluginManager* manager = KReportPluginManager::self();
1473     QList<QAction*> actList = manager->createActions(group);
1474 
1475     //! @todo make line a real plugin so this isn't needed:
1476     QAction *act = new QAction(QIcon::fromTheme(QLatin1String("kreport-line-element")), tr("Line"), group);
1477     act->setObjectName(QLatin1String("org.kde.kreport.line"));
1478     act->setData(9);
1479     act->setCheckable(true);
1480     actList << act;
1481 
1482     std::sort(actList.begin(), actList.end(), actionPriortyLessThan);
1483     int i = 0;
1484 
1485     /*! @todo maybe this is a bit hackish
1486      It finds the first plugin based on the priority in userdata
1487      The lowest oriority a plugin can have is 10
1488      And inserts a separator before it. */
1489     bool sepInserted = false;
1490     foreach(QAction *a, actList) {
1491         ++i;
1492         if (!sepInserted && a->data().toInt() >= 10) {
1493             QAction *sep = new QAction(QLatin1String("separator"), group);
1494             sep->setSeparator(true);
1495             actList.insert(i-1, sep);
1496             sepInserted = true;
1497         }
1498         if (group) {
1499             group->addAction(a);
1500         }
1501     }
1502 
1503     return actList;
1504 }
1505 
1506 QList< QAction* > KReportDesigner::designerActions()
1507 {
1508     QList<QAction*> al;
1509     QAction *sep = new QAction(QString(), this);
1510     sep->setSeparator(true);
1511 
1512     al << d->editCutAction << d->editCopyAction << d->editPasteAction << d->editDeleteAction << sep << d->sectionEdit << sep << d->itemLowerAction << d->itemRaiseAction;
1513 
1514     return al;
1515 }
1516 
1517 void KReportDesigner::createActions()
1518 {
1519     d->editCutAction = new QAction(QIcon::fromTheme(QLatin1String("edit-cut")), tr("Cu&t"), this);
1520     d->editCutAction->setObjectName(QLatin1String("edit_cut"));
1521     d->editCutAction->setToolTip(tr("Cut selection to clipboard"));
1522     d->editCutAction->setShortcuts(KStandardShortcut::cut());
1523     d->editCutAction->setProperty("iconOnly", true);
1524 
1525     d->editCopyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), tr("&Copy"), this);
1526     d->editCopyAction->setObjectName(QLatin1String("edit_copy"));
1527     d->editCopyAction->setToolTip(tr("Copy selection to clipboard"));
1528     d->editCopyAction->setShortcuts(KStandardShortcut::copy());
1529     d->editCopyAction->setProperty("iconOnly", true);
1530 
1531     d->editPasteAction = new QAction(QIcon::fromTheme(QLatin1String("edit-paste")), tr("&Paste"), this);
1532     d->editPasteAction->setObjectName(QLatin1String("edit_paste"));
1533     d->editPasteAction->setToolTip(tr("Paste clipboard content"));
1534     d->editPasteAction->setShortcuts(KStandardShortcut::paste());
1535     d->editPasteAction->setProperty("iconOnly", true);
1536 
1537     const KGuiItem del = KStandardGuiItem::del();
1538     d->editDeleteAction = new QAction(del.icon(), del.text(), this);
1539     d->editDeleteAction->setObjectName(QLatin1String("edit_delete"));
1540     d->editDeleteAction->setToolTip(del.toolTip());
1541     d->editDeleteAction->setWhatsThis(del.whatsThis());
1542     d->editDeleteAction->setProperty("iconOnly", true);
1543 
1544     d->sectionEdit = new QAction(tr("Edit Sections"), this);
1545     d->sectionEdit->setObjectName(QLatin1String("section_edit"));
1546 
1547     d->itemRaiseAction = new QAction(QIcon::fromTheme(QLatin1String("arrow-up")), tr("Raise"), this);
1548     d->itemRaiseAction->setObjectName(QLatin1String("item_raise"));
1549     d->itemLowerAction = new QAction(QIcon::fromTheme(QLatin1String("arrow-down")), tr("Lower"), this);
1550     d->itemLowerAction->setObjectName(QLatin1String("item_lower"));
1551 
1552     //Edit Actions
1553     connect(d->editCutAction, SIGNAL(triggered(bool)), this, SLOT(slotEditCut()));
1554     connect(d->editCopyAction, SIGNAL(triggered(bool)), this, SLOT(slotEditCopy()));
1555     connect(d->editPasteAction, SIGNAL(triggered(bool)), this, SLOT(slotEditPaste()));
1556     connect(d->editDeleteAction, SIGNAL(triggered(bool)), this, SLOT(slotEditDelete()));
1557 
1558     connect(d->sectionEdit, SIGNAL(triggered(bool)), this, SLOT(slotSectionEditor()));
1559 
1560     //Raise/Lower
1561     connect(d->itemRaiseAction, SIGNAL(triggered(bool)), this, SLOT(slotRaiseSelected()));
1562     connect(d->itemLowerAction, SIGNAL(triggered(bool)), this, SLOT(slotLowerSelected()));
1563 }
1564 
1565 void KReportDesigner::setSectionCursor(const QCursor& c)
1566 {
1567     if (d->pageFooterAny)
1568         d->pageFooterAny->setSectionCursor(c);
1569     if (d->pageFooterEven)
1570         d->pageFooterEven->setSectionCursor(c);
1571     if (d->pageFooterFirst)
1572         d->pageFooterFirst->setSectionCursor(c);
1573     if (d->pageFooterLast)
1574         d->pageFooterLast->setSectionCursor(c);
1575     if (d->pageFooterOdd)
1576         d->pageFooterOdd->setSectionCursor(c);
1577 
1578     if (d->pageHeaderAny)
1579         d->pageHeaderAny->setSectionCursor(c);
1580     if (d->pageHeaderEven)
1581         d->pageHeaderEven->setSectionCursor(c);
1582     if (d->pageHeaderFirst)
1583         d->pageHeaderFirst->setSectionCursor(c);
1584     if (d->pageHeaderLast)
1585         d->pageHeaderLast->setSectionCursor(c);
1586     if (d->pageHeaderOdd)
1587         d->pageHeaderOdd->setSectionCursor(c);
1588 
1589     if (d->detail)
1590         d->detail->setSectionCursor(c);
1591 }
1592 
1593 void KReportDesigner::unsetSectionCursor()
1594 {
1595     if (d->pageFooterAny)
1596         d->pageFooterAny->unsetSectionCursor();
1597     if (d->pageFooterEven)
1598         d->pageFooterEven->unsetSectionCursor();
1599     if (d->pageFooterFirst)
1600         d->pageFooterFirst->unsetSectionCursor();
1601     if (d->pageFooterLast)
1602         d->pageFooterLast->unsetSectionCursor();
1603     if (d->pageFooterOdd)
1604         d->pageFooterOdd->unsetSectionCursor();
1605 
1606     if (d->pageHeaderAny)
1607         d->pageHeaderAny->unsetSectionCursor();
1608     if (d->pageHeaderEven)
1609         d->pageHeaderEven->unsetSectionCursor();
1610     if (d->pageHeaderFirst)
1611         d->pageHeaderFirst->unsetSectionCursor();
1612     if (d->pageHeaderLast)
1613         d->pageHeaderLast->unsetSectionCursor();
1614     if (d->pageHeaderOdd)
1615         d->pageHeaderOdd->unsetSectionCursor();
1616 
1617     if (d->detail)
1618         d->detail->unsetSectionCursor();
1619 }
1620 
1621 qreal KReportDesigner::countSelectionHeight() const
1622 {
1623     if (d->releaseY == -1 || d->pressY == -1) {
1624         return -1;
1625     }
1626     return qAbs(d->releaseY - d->pressY);
1627 }
1628 
1629 qreal KReportDesigner::countSelectionWidth() const
1630 {
1631     if (d->releaseX == -1 || d->pressX == -1) {
1632         return -1;
1633     }
1634     return qAbs(d->releaseX - d->pressX);
1635 }
1636 
1637 qreal KReportDesigner::getSelectionPressX() const
1638 {
1639     return d->pressX;
1640 }
1641 
1642 qreal KReportDesigner::getSelectionPressY() const
1643 {
1644     return d->pressY;
1645 }
1646 
1647 QPointF KReportDesigner::getPressPoint() const
1648 {
1649     return QPointF(d->pressX, d->pressY);
1650 }
1651 
1652 QPointF KReportDesigner::getReleasePoint() const
1653 {
1654     return QPointF(d->releaseX, d->releaseY);
1655 }
1656 
1657 void KReportDesigner::plugItemActions(const QList<QAction*> &actList)
1658 {
1659     foreach(QAction *a, actList) {
1660         connect(a, SIGNAL(triggered(bool)), this, SLOT(slotItemTriggered(bool)));
1661     }
1662 }
1663 
1664 void KReportDesigner::slotItemTriggered(bool checked)
1665 {
1666     if (!checked) {
1667         return;
1668     }
1669     QObject *theSender = sender();
1670     if (!theSender) {
1671         return;
1672     }
1673     slotItem(theSender->objectName());
1674 }
1675 
1676 void KReportDesigner::addMetaProperties(KPropertySet* set, const QString &classString,
1677                                         const QString &iconName)
1678 {
1679     Q_ASSERT(set);
1680     KProperty *prop;
1681     set->addProperty(prop = new KProperty("this:classString", classString));
1682     prop->setVisible(false);
1683     set->addProperty(prop = new KProperty("this:iconName", iconName));
1684     prop->setVisible(false);
1685 }
1686 
1687 void KReportDesigner::recalculateMaxMargins()
1688 {
1689     QSize pageSize = pageSizePt();
1690     d->leftMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.width() - d->currentUnit.convertToPoint(d->rightMargin->value().toReal()) - SMALLEST_PAGE_SIZE_PT));
1691     d->rightMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.width()  - d->currentUnit.convertToPoint(d->leftMargin->value().toReal())- SMALLEST_PAGE_SIZE_PT));
1692     d->topMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.height()  - d->currentUnit.convertToPoint(d->bottomMargin->value().toReal())- SMALLEST_PAGE_SIZE_PT));
1693     d->bottomMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.height()  - d->currentUnit.convertToPoint(d->topMargin->value().toReal())- SMALLEST_PAGE_SIZE_PT));
1694 }