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 }