KReport

KReportDesigner.cpp
1/* This file is part of the KDE project
2 * Copyright (C) 2001-2007 by OpenMFG, LLC <info@openmfg.com>
3 * Copyright (C) 2007-2010 by Adam Pigg <adam@piggz.co.uk>
4 * Copyright (C) 2011-2017 Jarosław Staniek <staniek@kde.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "KReportDesigner.h"
21#include "KReportDesign_p.h"
22#include "KReportDesignerItemLine.h"
23#include "KReportDesignerSection.h"
24#include "KReportDesignerSectionDetail.h"
25#include "KReportDesignerSectionDetailGroup.h"
26#include "KReportDesignerSectionScene.h"
27#include "KReportDesignerSectionView.h"
28#include "KReportPageSize.h"
29#include "KReportPluginInterface.h"
30#include "KReportPluginManager.h"
31#include "KReportPluginMetaData.h"
32#include "KReportPropertiesButton.h"
33#include "KReportRuler_p.h"
34#include "KReportSection.h"
35#include "KReportSectionEditor.h"
36#include "KReportUtils.h"
37#include "KReportUtils_p.h"
38#include "KReportZoomHandler_p.h"
39#include "kreport_debug.h"
40#ifdef KREPORT_SCRIPTING
41#include "KReportScriptSource.h"
42#endif
43
44#include <KPropertyListData>
45
46#include <KStandardShortcut>
47#include <KStandardGuiItem>
48#include <QLayout>
49#include <QDomDocument>
50#include <QVBoxLayout>
51#include <QGridLayout>
52#include <QGraphicsSceneMouseEvent>
53#include <QMenu>
54#include <QPointer>
55#include <QIcon>
56#include <QAction>
57#include <QMouseEvent>
58#include <QMessageBox>
59
60//! Also add public method for runtime?
61const char ns[] = "http://kexi-project.org/report/2.0";
62
63static QDomElement propertyToElement(QDomDocument* d, KProperty* p)
64{
65 QDomElement e = d->createElement(QLatin1String("report:" + p->name().toLower()));
67 return e;
68}
69
70//
71// define and implement the ReportWriterSectionData class
72// a simple class to hold/hide data in the ReportHandler class
73//
74class ReportWriterSectionData
75{
76public:
77 ReportWriterSectionData() {
78 selected_x_offset = 0;
79 selected_y_offset = 0;
80 mouseAction = MouseAction::None;
81 }
82 virtual ~ReportWriterSectionData() {
83 }
84
85 enum class MouseAction {
86 None = 0,
87 Insert = 1,
88 Grab = 2,
89 MoveStartPoint,
90 MoveEndPoint,
91 ResizeNW = 8,
92 ResizeN,
93 ResizeNE,
94 ResizeE,
95 ResizeSE,
96 ResizeS,
97 ResizeSW,
98 ResizeW
99 };
100
101 int selected_x_offset;
102 int selected_y_offset;
103
104 MouseAction mouseAction;
105 QString itemToInsert;
106
109};
110
111//! @internal
112class Q_DECL_HIDDEN KReportDesigner::Private
113{
114public:
115 explicit Private(KReportDesigner *designer);
116
117 ~Private()
118 {
119 delete dataSource;
120 }
121
122 void init(const QDomElement *xml);
123
124 void updateCurrentUnit() {
125 QString u = unit->value().toString();
127 if (newUnit.isValid()) {
128 currentUnit = newUnit;
129 } else {
130 currentUnit = DEFAULT_UNIT;
131 }
132
133 if (u == QLatin1String("dm")) {
134 gridDivisions->setOption("max", 100);
135 } else {
136 gridDivisions->setOption("max", 10);
137 if (gridDivisions->value().toInt() > 10) {
138 gridDivisions->setValue(10, KProperty::ValueOption::IgnoreOld);
139 }
140 }
141 }
142
143#ifdef KREPORT_SCRIPTING
144 void updateScripts();
145#endif
146
147 KReportDesigner * const q;
148
149 QGridLayout *grid;
150 KReportRuler *hruler;
151 KReportZoomHandler zoomHandler;
152 QVBoxLayout *vboxlayout;
153 KReportPropertiesButton *pageButton;
154
155 QGraphicsScene *activeScene = nullptr;
156
157 ReportWriterSectionData sectionData;
158
159 KReportDesignerSection *reportHeader = nullptr;
160 KReportDesignerSection *pageHeaderFirst = nullptr;
161 KReportDesignerSection *pageHeaderOdd = nullptr;
162 KReportDesignerSection *pageHeaderEven = nullptr;
163 KReportDesignerSection *pageHeaderLast = nullptr;
164 KReportDesignerSection *pageHeaderAny = nullptr;
165
166 KReportDesignerSection *pageFooterFirst = nullptr;
167 KReportDesignerSection *pageFooterOdd = nullptr;
168 KReportDesignerSection *pageFooterEven = nullptr;
169 KReportDesignerSection *pageFooterLast = nullptr;
170 KReportDesignerSection *pageFooterAny = nullptr;
171 KReportDesignerSection *reportFooter = nullptr;
172 KReportDesignerSectionDetail *detail = nullptr;
173
174 //Properties
175 KPropertySet set;
176 KPropertySet *itemSet;
177 KProperty *title;
179 KProperty *orientation;
180 KProperty *unit;
181 KProperty *customPageSize;
182 KProperty *leftMargin;
183 KProperty *rightMargin;
184 KProperty *topMargin;
185 KProperty *bottomMargin;
186 KProperty *showGrid;
187 KProperty *gridDivisions;
188 KProperty *gridSnap;
189 KProperty *labelType;
190#ifdef KREPORT_SCRIPTING
191 KProperty *script;
192#endif
193
194 KReportUnit currentUnit;
195
196 //Actions
197 QAction *editCutAction;
198 QAction *editCopyAction;
199 QAction *editPasteAction;
200 QAction *editDeleteAction;
201 QAction *sectionEdit;
202 QAction *parameterEdit;
203 QAction *itemRaiseAction;
204 QAction *itemLowerAction;
205
206 qreal pressX = -1;
207 qreal pressY = -1;
208 qreal releaseX = -1;
209 qreal releaseY = -1;
210
211 bool modified = false; // true if this document has been modified, false otherwise
212
213 QString originalInterpreter; //Value of the script interpreter at load time
214 QString originalScript; //Value of the script at load time
215
216 KReportDataSource *dataSource = nullptr;
217#ifdef KREPORT_SCRIPTING
218 KReportScriptSource *scriptSource = nullptr;
219#endif
220
221private:
222 void loadXml(const QDomElement &data);
223};
224
225KReportDesigner::Private::Private(KReportDesigner *designer)
226 : q(designer), currentUnit(DEFAULT_UNIT_TYPE)
227{
228}
229
230// (must be init() instead of ctor because we are indirectly depending on initialized KReportDesigner::d here)
231void KReportDesigner::Private::init(const QDomElement *xml)
232{
233 KReportPluginManager::self(); // this loads icons early enough
234
235 q->createProperties();
236 q->createActions();
237
238 grid = new QGridLayout(q);
239 grid->setSpacing(0);
240 grid->setMargin(0);
241 grid->setColumnStretch(1, 1);
242 grid->setRowStretch(1, 1);
244
245 vboxlayout = new QVBoxLayout();
246 vboxlayout->setSpacing(0);
247 vboxlayout->setMargin(0);
249
250 //Create nice rulers
251 hruler = new KReportRuler(nullptr, Qt::Horizontal, zoomHandler);
252 hruler->setUnit(DEFAULT_UNIT);
253
254 pageButton = new KReportPropertiesButton;
255
256 grid->addWidget(pageButton, 0, 0);
257 grid->addWidget(hruler, 0, 1);
258 grid->addLayout(vboxlayout, 1, 0, 1, 2);
259
260 pageButton->setMaximumSize(QSize(19, 22));
261 pageButton->setMinimumSize(QSize(19, 22));
262
263 if (!xml) {
264 detail = new KReportDesignerSectionDetail(q);
265 vboxlayout->insertWidget(0, detail);
266 }
267
269 q, &KReportDesigner::slotPageButton_Pressed);
270 emit q->pagePropertyChanged(set);
271
272 connect(&set, &KPropertySet::propertyChanged, q, &KReportDesigner::slotPropertyChanged);
273
274 if (xml) {
275 loadXml(*xml);
276 }
277 set.clearModifiedFlags();
278 q->changeSet(&set);
279}
280
281void KReportDesigner::Private::loadXml(const QDomElement &data)
282{
283 if (data.tagName() != QLatin1String("report:content")) {
284 // arg we got an xml file but not one i know of
285 kreportWarning() << "root element was not <report:content>";
286 }
287 //kreportDebug() << data.text();
288
289 QDomNodeList nlist = data.childNodes();
290 QDomNode it;
291
292 for (int i = 0; i < nlist.count(); ++i) {
293 it = nlist.item(i);
294 // at this level all the children we get should be Elements
295 if (it.isElement()) {
296 QString n = it.nodeName().toLower();
297 //kreportDebug() << n;
298 if (n == QLatin1String("report:title")) {
299 q->setReportTitle(it.firstChild().nodeValue());
300#ifdef KREPORT_SCRIPTING
301 } else if (n == QLatin1String("report:script")) {
302 originalInterpreter = it.toElement().attribute(QLatin1String("report:script-interpreter"), QLatin1String("javascript"));
303 if (originalInterpreter.isEmpty()) {
304 originalInterpreter = QLatin1String("javascript");
305 }
306 originalScript = it.firstChild().nodeValue();
307 script->setValue(originalScript);
308
309 if (originalInterpreter != QLatin1String("javascript") && originalInterpreter != QLatin1String("qtscript")) {
310 QString msg = tr("This report contains scripts of type \"%1\". "
311 "Only scripts written in JavaScript language are "
312 "supported. To prevent losing the scripts, their type "
313 "and content will not be changed unless you change these scripts."
314 ).arg(originalInterpreter);
315 QMessageBox::warning(q, tr("Unsupported Script Type"), msg);
316 }
317#endif
318 } else if (n == QLatin1String("report:grid")) {
319 showGrid->setValue(it.toElement().attribute(QLatin1String("report:grid-visible"), QString::number(1)).toInt() != 0);
320 gridSnap->setValue(it.toElement().attribute(QLatin1String("report:grid-snap"), QString::number(1)).toInt() != 0);
321 gridDivisions->setValue(it.toElement().attribute(QLatin1String("report:grid-divisions"), QString::number(4)).toInt());
322 unit->setValue(it.toElement().attribute(QLatin1String("report:page-unit"), DEFAULT_UNIT_STRING));
323 updateCurrentUnit();
324 }
325
326 //! @todo Load page options
327 else if (n == QLatin1String("report:page-style")) {
328 QString pagetype = it.firstChild().nodeValue();
329
330 if (pagetype == QLatin1String("predefined")) {
331 pageSize->setValue(it.toElement().attribute(QLatin1String("report:page-size"), QLatin1String("A4")));
332 } else if (pagetype == QLatin1String("custom")) {
333 pageSize->setValue(QLatin1String("Custom"));
334 customPageSize->setValue(QSizeF(KReportUnit::parseValue(it.toElement().attribute(QLatin1String("report:custom-page-width"), QLatin1String(""))),
335 KReportUnit::parseValue(it.toElement().attribute(QLatin1String("report:custom-page-height"), QLatin1String("")))));
336 } else if (pagetype == QLatin1String("label")) {
337 //! @todo
338 }
339
340 rightMargin->setValue(currentUnit.convertFromPoint(
342 QLatin1String("fo:margin-right"), DEFAULT_PAGE_MARGIN_STRING))));
343 leftMargin->setValue(currentUnit.convertFromPoint(
345 QLatin1String("fo:margin-left"), DEFAULT_PAGE_MARGIN_STRING))));
346 topMargin->setValue(currentUnit.convertFromPoint(
348 QLatin1String("fo:margin-top"), DEFAULT_PAGE_MARGIN_STRING))));
349 bottomMargin->setValue(currentUnit.convertFromPoint(
351 QLatin1String("fo:margin-bottom"), DEFAULT_PAGE_MARGIN_STRING))));
352 orientation->setValue(
353 it.toElement().attribute(QLatin1String("report:print-orientation"),
354 QLatin1String("portrait")));
355 } else if (n == QLatin1String("report:body")) {
356 QDomNodeList sectionlist = it.childNodes();
357 QDomNode sec;
358
359 for (int s = 0; s < sectionlist.count(); ++s) {
360 sec = sectionlist.item(s);
361 if (sec.isElement()) {
362 QString sn = sec.nodeName().toLower();
363 //kreportDebug() << sn;
364 if (sn == QLatin1String("report:section")) {
365 const QString sectiontype = KReportUtils::readSectionTypeNameAttribute(sec.toElement());
366 if (q->section(KReportSectionData::sectionTypeFromString(sectiontype)) == nullptr) {
367 q->insertSection(KReportSectionData::sectionTypeFromString(sectiontype));
368 q->section(KReportSectionData::sectionTypeFromString(sectiontype))->initFromXML(sec);
369 }
370 } else if (sn == QLatin1String("report:detail")) {
372 rsd->initFromXML(&sec);
373 q->setDetail(rsd);
374 }
375 } else {
376 kreportWarning() << "Encountered an unknown Element: " << n;
377 }
378 }
379 }
380 } else {
381 kreportWarning() << "Encountered a child node of root that is not an Element";
382 }
383 }
384 updateScripts();
385 emit q->reportDataChanged();
386 q->slotPropertyChanged(set, *unit); // set unit for all items
387 q->setModified(false);
388}
389
390#ifdef KREPORT_SCRIPTING
391void KReportDesigner::Private::updateScripts()
392{
393 if (scriptSource) {
394 QStringList sl = scriptSource->scriptList();
395 sl.prepend(QString()); // prepend "none"
396 script->setListData(sl, sl);
397 }
398}
399#endif
400
401// ----
402
404 : QWidget(parent), d(new Private(this))
405{
406 d->init(nullptr);
407}
408
410 : QWidget(parent), d(new Private(this))
411{
412 d->init(&data);
413}
414
416{
417 delete d;
418}
419
420///The saving code
422{
423 QDomDocument doc;
424 QString saveInterpreter;
425
426 QDomElement content = doc.createElement(QLatin1String("report:content"));
427 content.setAttribute(QLatin1String("xmlns:report"), QLatin1String(ns));
428 content.setAttribute(QLatin1String("xmlns:fo"), QLatin1String("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"));
429 content.setAttribute(QLatin1String("xmlns:svg"), QLatin1String("urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"));
430
431 doc.appendChild(content);
432
433 //title
434 content.appendChild(propertyToElement(&doc, d->title));
435
436#ifdef KREPORT_SCRIPTING
437 if (d->originalInterpreter.isEmpty()) {
438 d->originalInterpreter = QLatin1String("javascript");
439 }
440 saveInterpreter = d->originalInterpreter;
441
442 if (!d->script->value().toString().isEmpty()) {
443 if (d->script->value().toString() != d->originalScript || d->originalInterpreter == QLatin1String("qtscript") || d->originalInterpreter.isEmpty() ) {
444 //The script has changed so force interpreter to 'javascript'. Also set if was using qtscript
445 saveInterpreter = QLatin1String("javascript");
446 }
447 }
448
449 QDomElement scr = propertyToElement(&doc, d->script);
450 scr.setAttribute(QLatin1String("report:script-interpreter"), saveInterpreter);
451 content.appendChild(scr);
452#endif
453
454 QDomElement grd = doc.createElement(QLatin1String("report:grid"));
455 KReportUtils::addPropertyAsAttribute(&grd, d->showGrid);
456 KReportUtils::addPropertyAsAttribute(&grd, d->gridDivisions);
457 KReportUtils::addPropertyAsAttribute(&grd, d->gridSnap);
458 KReportUtils::addPropertyAsAttribute(&grd, d->unit);
459 content.appendChild(grd);
460
461 // pageOptions
462 // -- size
463 QDomElement pagestyle = doc.createElement(QLatin1String("report:page-style"));
464
465 if (d->pageSize->value().toString() == QLatin1String("Custom")) {
466 pagestyle.appendChild(doc.createTextNode(QLatin1String("custom")));
467
468 KReportUtils::setAttribute(
469 &pagestyle, QLatin1String("report:custom-page-width"),
470 d->currentUnit.convertToPoint(d->customPageSize->value().toSizeF().width()));
471 KReportUtils::setAttribute(
472 &pagestyle, QLatin1String("report:custom-page-height"),
473 d->currentUnit.convertToPoint(d->customPageSize->value().toSizeF().height()));
474 } else if (d->pageSize->value().toString() == QLatin1String("Label")) {
475 pagestyle.appendChild(doc.createTextNode(QLatin1String("label")));
476 pagestyle.setAttribute(QLatin1String("report:page-label-type"), d->labelType->value().toString());
477 } else {
478 pagestyle.appendChild(doc.createTextNode(QLatin1String("predefined")));
479 KReportUtils::addPropertyAsAttribute(&pagestyle, d->pageSize);
480 //pagestyle.setAttribute("report:page-size", d->pageSize->value().toString());
481 }
482
483 // -- orientation
484 KReportUtils::addPropertyAsAttribute(&pagestyle, d->orientation);
485
486 // -- margins: save as points, and not localized
487 KReportUtils::setAttribute(
488 &pagestyle, QLatin1String("fo:margin-top"),
489 d->currentUnit.convertToPoint(d->topMargin->value().toDouble()));
490 KReportUtils::setAttribute(
491 &pagestyle, QLatin1String("fo:margin-bottom"),
492 d->currentUnit.convertToPoint(d->bottomMargin->value().toDouble()));
493 KReportUtils::setAttribute(
494 &pagestyle, QLatin1String("fo:margin-right"),
495 d->currentUnit.convertToPoint(d->rightMargin->value().toDouble()));
496 KReportUtils::setAttribute(
497 &pagestyle, QLatin1String("fo:margin-left"),
498 d->currentUnit.convertToPoint(d->leftMargin->value().toDouble()));
499
500 content.appendChild(pagestyle);
501
502 QDomElement body = doc.createElement(QLatin1String("report:body"));
503 QDomElement domsection;
504
505 for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
506 i <= static_cast<int>(KReportSectionData::Type::PageFooterAny); ++i)
507 {
508 KReportDesignerSection *sec = section(static_cast<KReportSectionData::Type>(i));
509 if (sec) {
510 domsection = doc.createElement(QLatin1String("report:section"));
511 domsection.setAttribute(
512 QLatin1String("report:section-type"),
513 KReportSectionData::sectionTypeString(static_cast<KReportSectionData::Type>(i)));
514 sec->buildXML(&doc, &domsection);
515 body.appendChild(domsection);
516 }
517 }
518
519 QDomElement detail = doc.createElement(QLatin1String("report:detail"));
520 d->detail->buildXML(&doc, &detail);
521 body.appendChild(detail);
522
523 content.appendChild(body);
524 return content;
525}
526
527void KReportDesigner::slotSectionEditor()
528{
529 KReportSectionEditor se(this);
530 (void)se.exec();
531}
532
534{
535 if (d->dataSource == source) {
536 return;
537 }
538 delete d->dataSource;
539
540 d->dataSource = source;
541 slotPageButton_Pressed();
542 setModified(true);
543 emit reportDataChanged();
544}
545
546#ifdef KREPORT_SCRIPTING
547void KReportDesigner::setScriptSource(KReportScriptSource* source)
548{
549 d->scriptSource = source;
550 d->updateScripts();
551}
552#endif
553
554KReportDesignerSection * KReportDesigner::section(KReportSectionData::Type type) const
555{
557 switch (type) {
558 case KReportSectionData::Type::PageHeaderAny:
559 sec = d->pageHeaderAny;
560 break;
561 case KReportSectionData::Type::PageHeaderEven:
562 sec = d->pageHeaderEven;
563 break;
564 case KReportSectionData::Type::PageHeaderOdd:
565 sec = d->pageHeaderOdd;
566 break;
567 case KReportSectionData::Type::PageHeaderFirst:
568 sec = d->pageHeaderFirst;
569 break;
570 case KReportSectionData::Type::PageHeaderLast:
571 sec = d->pageHeaderLast;
572 break;
573 case KReportSectionData::Type::PageFooterAny:
574 sec = d->pageFooterAny;
575 break;
576 case KReportSectionData::Type::PageFooterEven:
577 sec = d->pageFooterEven;
578 break;
579 case KReportSectionData::Type::PageFooterOdd:
580 sec = d->pageFooterOdd;
581 break;
582 case KReportSectionData::Type::PageFooterFirst:
583 sec = d->pageFooterFirst;
584 break;
585 case KReportSectionData::Type::PageFooterLast:
586 sec = d->pageFooterLast;
587 break;
588 case KReportSectionData::Type::ReportHeader:
589 sec = d->reportHeader;
590 break;
591 case KReportSectionData::Type::ReportFooter:
592 sec = d->reportFooter;
593 break;
594 default:
595 sec = nullptr;
596 }
597 return sec;
598}
599
601{
602 return new KReportDesignerSection(this, d->zoomHandler);
603}
604
605void KReportDesigner::removeSection(KReportSectionData::Type type)
606{
607 KReportDesignerSection* sec = section(type);
608 if (sec) {
609 delete sec;
610
611 switch (type) {
612 case KReportSectionData::Type::PageHeaderAny:
613 d->pageHeaderAny = nullptr;
614 break;
615 case KReportSectionData::Type::PageHeaderEven:
616 sec = d->pageHeaderEven = nullptr;
617 break;
618 case KReportSectionData::Type::PageHeaderOdd:
619 d->pageHeaderOdd = nullptr;
620 break;
621 case KReportSectionData::Type::PageHeaderFirst:
622 d->pageHeaderFirst = nullptr;
623 break;
624 case KReportSectionData::Type::PageHeaderLast:
625 d->pageHeaderLast = nullptr;
626 break;
627 case KReportSectionData::Type::PageFooterAny:
628 d->pageFooterAny = nullptr;
629 break;
630 case KReportSectionData::Type::PageFooterEven:
631 d->pageFooterEven = nullptr;
632 break;
633 case KReportSectionData::Type::PageFooterOdd:
634 d->pageFooterOdd = nullptr;
635 break;
636 case KReportSectionData::Type::PageFooterFirst:
637 d->pageFooterFirst = nullptr;
638 break;
639 case KReportSectionData::Type::PageFooterLast:
640 d->pageFooterLast = nullptr;
641 break;
642 case KReportSectionData::Type::ReportHeader:
643 d->reportHeader = nullptr;
644 break;
645 case KReportSectionData::Type::ReportFooter:
646 d->reportFooter = nullptr;
647 break;
648 default:
649 sec = nullptr;
650 }
651
652 setModified(true);
653 adjustSize();
654 }
655}
656
657void KReportDesigner::insertSection(KReportSectionData::Type type)
658{
659 KReportDesignerSection* sec = section(type);
660 if (!sec) {
661 int idx = 0;
662 for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
663 i <= static_cast<int>(type); ++i)
664 {
665 if (section(static_cast<KReportSectionData::Type>(i)))
666 idx++;
667 }
668 if (type > KReportSectionData::Type::ReportHeader)
669 idx++;
670 //kreportDebug() << idx;
672 d->vboxlayout->insertWidget(idx, rs);
673
674 switch (type) {
675 case KReportSectionData::Type::PageHeaderAny:
676 rs->setTitle(tr("Page Header (Any)"));
677 d->pageHeaderAny = rs;
678 break;
679 case KReportSectionData::Type::PageHeaderEven:
680 rs->setTitle(tr("Page Header (Even)"));
681 d->pageHeaderEven = rs;
682 break;
683 case KReportSectionData::Type::PageHeaderOdd:
684 rs->setTitle(tr("Page Header (Odd)"));
685 d->pageHeaderOdd = rs;
686 break;
687 case KReportSectionData::Type::PageHeaderFirst:
688 rs->setTitle(tr("Page Header (First)"));
689 d->pageHeaderFirst = rs;
690 break;
691 case KReportSectionData::Type::PageHeaderLast:
692 rs->setTitle(tr("Page Header (Last)"));
693 d->pageHeaderLast = rs;
694 break;
695 case KReportSectionData::Type::PageFooterAny:
696 rs->setTitle(tr("Page Footer (Any)"));
697 d->pageFooterAny = rs;
698 break;
699 case KReportSectionData::Type::PageFooterEven:
700 rs->setTitle(tr("Page Footer (Even)"));
701 d->pageFooterEven = rs;
702 break;
703 case KReportSectionData::Type::PageFooterOdd:
704 rs->setTitle(tr("Page Footer (Odd)"));
705 d->pageFooterOdd = rs;
706 break;
707 case KReportSectionData::Type::PageFooterFirst:
708 rs->setTitle(tr("Page Footer (First)"));
709 d->pageFooterFirst = rs;
710 break;
711 case KReportSectionData::Type::PageFooterLast:
712 rs->setTitle(tr("Page Footer (Last)"));
713 d->pageFooterLast = rs;
714 break;
715 case KReportSectionData::Type::ReportHeader:
716 rs->setTitle(tr("Report Header"));
717 d->reportHeader = rs;
718 break;
719 case KReportSectionData::Type::ReportFooter:
720 rs->setTitle(tr("Report Footer"));
721 d->reportFooter = rs;
722 break;
723 //These sections cannot be inserted this way
724 case KReportSectionData::Type::None:
725 case KReportSectionData::Type::GroupHeader:
726 case KReportSectionData::Type::GroupFooter:
727 case KReportSectionData::Type::Detail:
728 break;
729 }
730
731 rs->show();
732 setModified(true);
733 adjustSize();
734 emit pagePropertyChanged(d->set);
735 }
736}
737
739{
740 if (reportTitle() != str) {
741 d->title->setValue(str);
742 setModified(true);
743 }
744}
745
747{
748 return &d->set;
749}
750
752{
753 return d->itemSet;
754}
755
757{
758 return d->dataSource;
759}
760
762{
763 return d->detail;
764}
765
767{
768 return d->title->value().toString();
769}
770
772{
773 return d->modified;
774}
775
777{
778 d->modified = modified;
779
780 if (d->modified) {
781 emit dirty();
782 }
783}
784
786{
787 QStringList qs;
788 qs << QString();
789 if (d->dataSource)
790 qs << d->dataSource->fieldNames();
791
792 return qs;
793}
794
796{
797 QStringList qs;
798 qs << QString();
799 if (d->dataSource)
800 qs << d->dataSource->fieldKeys();
801
802 return qs;
803}
804
805void KReportDesigner::createProperties()
806{
808 tr("Report", "Main report element"), QLatin1String("kreport-report-element"));
809
810 connect(&d->set, SIGNAL(propertyChanged(KPropertySet&,KProperty&)),
811 this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&)));
812
813 d->title = new KProperty("title", QLatin1String("Report"), tr("Title"), tr("Report Title"));
814
818 d->pageSize = new KProperty("page-size", listData, defaultKey, tr("Page Size"));
819
820 d->customPageSize = new KProperty("custom-page-size", DEFAULT_CUSTOM_PAGE_SIZE,
821 tr("Custom Page Size"), tr("Custom Page Size"), KProperty::SizeF);
822 d->customPageSize->setOption("suffix", d->currentUnit.symbol());
823
824 listData = new KPropertyListData({ QLatin1String("portrait"), QLatin1String("landscape") },
825 QVariantList{ tr("Portrait"), tr("Landscape") });
826 d->orientation = new KProperty("print-orientation", listData, QLatin1String("portrait"),
827 tr("Page Orientation"));
828
830 types.removeOne(KReportUnit::Type::Pixel);
832 d->unit = new KProperty("page-unit", listData, DEFAULT_UNIT_STRING, tr("Page Unit"));
833 d->showGrid = new KProperty("grid-visible", true, tr("Show Grid"));
834 d->gridSnap = new KProperty("grid-snap", true, tr("Snap to Grid"));
835 d->gridDivisions = new KProperty("grid-divisions", 4, tr("Grid Divisions"));
836 d->gridDivisions->setOption("min", 1);
837 d->gridDivisions->setOption("max", 10);
838
839
840 d->leftMargin = new KProperty("margin-left", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
841 tr("Left Margin"), tr("Left Margin"), KProperty::Double);
842 d->rightMargin = new KProperty("margin-right", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
843 tr("Right Margin"), tr("Right Margin"), KProperty::Double);
844 d->topMargin = new KProperty("margin-top", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
845 tr("Top Margin"), tr("Top Margin"), KProperty::Double);
846 d->bottomMargin = new KProperty("margin-bottom", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
847 tr("Bottom Margin"), tr("Bottom Margin"), KProperty::Double);
848 d->leftMargin->setOption("suffix", d->currentUnit.symbol());
849 d->rightMargin->setOption("suffix", d->currentUnit.symbol());
850 d->topMargin->setOption("suffix", d->currentUnit.symbol());
851 d->bottomMargin->setOption("suffix", d->currentUnit.symbol());
852
853 d->set.addProperty(d->title);
854 d->set.addProperty(d->pageSize);
855 d->set.addProperty(d->customPageSize);
856 d->set.addProperty(d->orientation);
857 d->set.addProperty(d->unit);
858 d->set.addProperty(d->gridSnap);
859 d->set.addProperty(d->showGrid);
860 d->set.addProperty(d->gridDivisions);
861 d->set.addProperty(d->leftMargin);
862 d->set.addProperty(d->rightMargin);
863 d->set.addProperty(d->topMargin);
864 d->set.addProperty(d->bottomMargin);
865
866 recalculateMaxMargins();
867
868#ifdef KREPORT_SCRIPTING
869 d->script = new KProperty("script", new KPropertyListData, QVariant(), tr("Object Script"));
870 d->set.addProperty(d->script);
871#endif
872}
873
874/**
875@brief Handle property changes
876*/
877void KReportDesigner::slotPropertyChanged(KPropertySet &s, KProperty &p)
878{
879 const QSignalBlocker blocker(s);
880 setModified(true);
881 QByteArray propertyName = p.name();
882
883 if (propertyName == "page-unit") {
884 const KReportUnit oldUnit = d->currentUnit;
885 d->updateCurrentUnit();
886 d->hruler->setUnit(pageUnit());
887
888 // convert values
889 d->leftMargin->setValue(KReportUnit::convertFromUnitToUnit(
890 d->leftMargin->value().toDouble(), oldUnit, d->currentUnit),
891 KProperty::ValueOption::IgnoreOld);
892
893 d->rightMargin->setValue(KReportUnit::convertFromUnitToUnit(
894 d->rightMargin->value().toDouble(), oldUnit, d->currentUnit),
895 KProperty::ValueOption::IgnoreOld);
896
897 d->topMargin->setValue(KReportUnit::convertFromUnitToUnit(d->topMargin->value().toDouble(),
898 oldUnit, d->currentUnit),
899 KProperty::ValueOption::IgnoreOld);
900
901 d->bottomMargin->setValue(KReportUnit::convertFromUnitToUnit(
902 d->bottomMargin->value().toDouble(), oldUnit, d->currentUnit),
903 KProperty::ValueOption::IgnoreOld);
904
905 d->customPageSize->setValue(
906 KReportUnit::convertFromUnitToUnit(d->customPageSize->value().toSizeF(), oldUnit,
907 d->currentUnit),
908 KProperty::ValueOption::IgnoreOld);
909
910 d->leftMargin->setOption("suffix", d->currentUnit.symbol());
911 d->rightMargin->setOption("suffix", d->currentUnit.symbol());
912 d->topMargin->setOption("suffix", d->currentUnit.symbol());
913 d->bottomMargin->setOption("suffix", d->currentUnit.symbol());
914 d->customPageSize->setOption("suffix", d->currentUnit.symbol());
915 } else if (propertyName.startsWith("margin-") || propertyName == "page-size" || propertyName == "custom-page-size") {
916 recalculateMaxMargins();
917 }
918 emit pagePropertyChanged(s);
919
920}
921
922void KReportDesigner::slotPageButton_Pressed()
923{
924#ifdef KREPORT_SCRIPTING
925 d->updateScripts();
926 changeSet(&d->set);
927#endif
928}
929
931{
932 int w = 0;
933 int h = 0;
934
935 if (d->pageFooterAny)
936 h += d->pageFooterAny->sizeHint().height();
937 if (d->pageFooterEven)
938 h += d->pageFooterEven->sizeHint().height();
939 if (d->pageFooterFirst)
940 h += d->pageFooterFirst->sizeHint().height();
941 if (d->pageFooterLast)
942 h += d->pageFooterLast->sizeHint().height();
943 if (d->pageFooterOdd)
944 h += d->pageFooterOdd->sizeHint().height();
945 if (d->pageHeaderAny)
946 h += d->pageHeaderAny->sizeHint().height();
947 if (d->pageHeaderEven)
948 h += d->pageHeaderEven->sizeHint().height();
949 if (d->pageHeaderFirst)
950 h += d->pageHeaderFirst->sizeHint().height();
951 if (d->pageHeaderLast)
952 h += d->pageHeaderLast->sizeHint().height();
953 if (d->pageHeaderOdd)
954 h += d->pageHeaderOdd->sizeHint().height();
955 if (d->reportHeader)
956 h += d->reportHeader->sizeHint().height();
957 if (d->reportFooter) {
958 h += d->reportFooter->sizeHint().height();
959
960 }
961 if (d->detail) {
962 h += d->detail->sizeHint().height();
963 w += d->detail->sizeHint().width();
964 }
965
966 h += d->hruler->height();
967
968 return QSize(w, h);
969}
970
972{
973 QSize pageSizePx;
974 int pageWidth;
975
976 if (d->set.property("page-size").value().toString() == QLatin1String("Custom")) {
977 KReportUnit unit = pageUnit();
978
979 QSizeF customSize = d->currentUnit.convertToPoint(d->set.property("custom-page-size").value().toSizeF());
980 QPageLayout layout(QPageSize(customSize, QPageSize::Point, QString(), QPageSize::ExactMatch), d->set.property("print-orientation").value().toString()
982
983 pageSizePx = layout.fullRectPixels(KReportPrivate::dpiX()).size();
984 } else {
986 QPageSize(KReportPageSize::pageSize(d->set.property("page-size").value().toString())),
987 d->set.property("print-orientation").value().toString()
989 pageSizePx = layout.fullRectPixels(KReportPrivate::dpiX()).size();
990 }
991
992 pageWidth = pageSizePx.width();
993
994 pageWidth = pageWidth - KReportUnit::convertFromUnitToUnit(d->set.property("margin-left").value().toDouble(), pageUnit(), KReportUnit(KReportUnit::Type::Inch)) * KReportPrivate::dpiX();
995 pageWidth = pageWidth - KReportUnit::convertFromUnitToUnit(d->set.property("margin-right").value().toDouble(), pageUnit(), KReportUnit(KReportUnit::Type::Inch)) * KReportPrivate::dpiX();
996
997 return pageWidth;
998}
999
1000QSize 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 {
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
1023void KReportDesigner::resizeEvent(QResizeEvent * event)
1024{
1025 Q_UNUSED(event);
1026 d->hruler->setRulerLength(pageWidthPx());
1027}
1028
1029void 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
1045{
1046 return d->currentUnit;
1047}
1048
1049void 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//
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
1096void 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
1103void 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
1170unsigned int KReportDesigner::selectionCount() const
1171{
1172 if (activeScene())
1173 return activeScene()->selectedItems().count();
1174 else
1175 return 0;
1176}
1177
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
1196void 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
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
1231void 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
1261void 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
1277void KReportDesigner::slotEditPaste()
1278{
1279 // call the editPaste function passing it a reportsection
1280 slotEditPaste(activeScene());
1281}
1282
1283void 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 {
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}
1326void KReportDesigner::slotRaiseSelected()
1327{
1328 dynamic_cast<KReportDesignerSectionScene*>(activeScene())->raiseSelected();
1329}
1330
1331void KReportDesigner::slotLowerSelected()
1332{
1333 dynamic_cast<KReportDesignerSectionScene*>(activeScene())->lowerSelected();
1334}
1335
1337{
1338 return d->activeScene;
1339}
1340
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
1352{
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
1395{
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
1462static 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
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
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
1517void 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
1565void 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
1593void 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
1622{
1623 if (d->releaseY == -1 || d->pressY == -1) {
1624 return -1;
1625 }
1626 return qAbs(d->releaseY - d->pressY);
1627}
1628
1630{
1631 if (d->releaseX == -1 || d->pressX == -1) {
1632 return -1;
1633 }
1634 return qAbs(d->releaseX - d->pressX);
1635}
1636
1638{
1639 return d->pressX;
1640}
1641
1643{
1644 return d->pressY;
1645}
1646
1648{
1649 return QPointF(d->pressX, d->pressY);
1650}
1651
1653{
1654 return QPointF(d->releaseX, d->releaseY);
1655}
1656
1657void 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
1664void 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
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
1687void 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}
QString iconName() const
QString name() const
void addProperty(KProperty *property, const QByteArray &group="common")
void clearModifiedFlags()
void propertyChanged(KPropertySet &set, KProperty &property)
void setVisible(bool visible)
QVariant value() const
QByteArray name() const
Abstraction of report data source.
Base class for report items used within the designer GUI.
The central detail section which contains the bulk of the report.
This class is the base to all Report Section's visual representation.
QGraphicsItemList items() const
Return the items in the section Only return top-level items ... ie, items with no parent item because...
The ReportDesigner is the main widget for designing a report.
void sectionMouseReleaseEvent(KReportDesignerSectionView *v, QMouseEvent *e)
Handle the mouse release event for a report section.
KReportDataSource * reportDataSource() const
Return a pointer to the reports data.
KReportDesignerSectionDetail * detailSection() const
Return a pointer to the detail section.
KReportUnit pageUnit() const
Return the current unit assigned to the report.
QList< QAction * > designerActions()
Populates the toolbar with actions that can be applied to the report Actions are created as children ...
QString suggestEntityName(const QString &name) const
Return a unique name that can be used by the entity.
bool isEntityNameUnique(const QString &name, KReportItemBase *ignore=nullptr) const
Checks if the supplied name is unique among all entities.
bool isModified() const
Return true if the design has been modified.
int pageWidthPx() const
Calculate the width of the page in pixels given the paper size, orientation, dpi and margin.
void setActiveScene(QGraphicsScene *scene)
Sets the active Scene.
void setDataSource(KReportDataSource *source)
Sets the report data The report data interface contains functions to retrieve data and information ab...
void setReportTitle(const QString &title)
Sets the title of the reportData.
void sectionContextMenuEvent(KReportDesignerSectionScene *scene, QGraphicsSceneContextMenuEvent *event)
Handle the context menu event for a report section.
QSize sizeHint() const override
Give a hint on the size of the widget.
void insertSection(KReportSectionData::Type type)
Create a new section and insert it into the report.
static QList< QAction * > itemActions(QActionGroup *group=nullptr)
Returns a list of actions that represent the entities that can be inserted into the report.
QString reportTitle() const
Return the title of the report.
void setGridOptions(bool visible, int divisions)
Sets the parameters for the display of the background gridpoints.
void setModified(bool modified)
Sets the modified status, defaulting to true for modified.
~KReportDesigner() override
Desctructor.
qreal getSelectionPressY() const
qreal getSelectionPressX() const
KReportDesignerSection * section(KReportSectionData::Type type) const
Return a pointer to the section specified.
QGraphicsScene * activeScene() const
QPointF getReleasePoint() const
KReportDesigner(QWidget *parent=nullptr)
Constructor that create a blank designer.
void changeSet(KPropertySet *set)
Sets the property set for the currently selected item.
qreal countSelectionHeight() const
KPropertySet * selectedItemPropertySet() const
Return the property set for the curently selected item.
QStringList fieldKeys() const
void removeSection(KReportSectionData::Type type)
Deletes the section specified.
QDomElement document() const
Return an XML description of the report.
QStringList fieldNames() const
KReportDesignerSection * createSection()
Creates new section.
KPropertySet * propertySet() const
static void addMetaProperties(KPropertySet *set, const QString &classString, const QString &iconName)
Adds meta-properties to the property set set for consumption by property editor.
QPointF getPressPoint() const
qreal countSelectionWidth() const
Base class for items that are drawn syncronously.
void setPosition(const QPointF &ptPos)
Sets position for the element.
static QPointF positionFromScene(const QPointF &pos)
Helper function mapping from screen units to points, pos is in pixels.
virtual QString typeName() const =0
Return the item type as a string.
An interface for plugins delivering KReport elements.
const KReportPluginMetaData * metaData() const
Manager class for finding and loading available plugins.
Abstraction of report script source.
static KReportSectionData::Type sectionTypeFromString(const QString &s)
static QString sectionTypeString(KReportSectionData::Type type)
Converts between different units.
Definition KReportUnit.h:71
static KReportUnit::Type symbolToType(const QString &symbol)
Returns a unit symbol string to type.
static qreal convertFromUnitToUnit(qreal value, const KReportUnit &fromUnit, const KReportUnit &toUnit, qreal factor=1.0)
convert the given value directly from one unit to another with high accuracy
static QList< Type > allTypes()
Returns list of all supported types (without Invalid)
bool isValid() const
Returns true if type of this unit is valid.
static QStringList symbols(const QList< Type > &types)
Returns the list of unit symbols for the given types.
static qreal parseValue(const QString &value, qreal defaultVal=0.0)
Parses common KReport and ODF values, like "10cm", "5mm" to pt.
static QStringList descriptions(const QList< Type > &types)
Returns the list of (translated) description strings for given list of types.
KREPORT_EXPORT QString pageSizeKey(QPageSize::PageSizeId id)
KREPORT_EXPORT QPageSize::PageSizeId pageSize(const QString &key)
KREPORT_EXPORT QStringList pageFormatKeys()
KREPORT_EXPORT QPageSize::PageSizeId defaultSize()
KREPORT_EXPORT QStringList pageFormatNames()
KGuiItem del()
const QList< QKeySequence > & cut()
const QList< QKeySequence > & paste()
const QList< QKeySequence > & copy()
QCA_EXPORT void init()
void setCheckable(bool)
QVariant data() const const
void setData(const QVariant &data)
void setSeparator(bool b)
QAction * addAction(QAction *action)
void insertWidget(int index, QWidget *widget, int stretch, Qt::Alignment alignment)
virtual void setSpacing(int spacing) override
bool startsWith(QByteArrayView bv) const const
QByteArray toLower() const const
QDomElement createElement(const QString &tagName)
QDomText createTextNode(const QString &value)
QString toString(int indent) const const
QString attribute(const QString &name, const QString &defValue) const const
void setAttribute(const QString &name, const QString &value)
QString tagName() const const
QDomNode appendChild(const QDomNode &newChild)
QDomNodeList childNodes() const const
void clear()
QDomNode firstChild() const const
bool isElement() const const
QString nodeName() const const
QString nodeValue() const const
QDomElement toElement() const const
int count() const const
QDomNode item(int index) const const
void accept()
QGraphicsScene * scene() const const
void setSelected(bool selected)
void setVisible(bool visible)
qreal x() const const
qreal y() const const
void addItem(QGraphicsItem *item)
void clearSelection()
qreal height() const const
void removeItem(QGraphicsItem *item)
QList< QGraphicsItem * > selectedItems() const const
void update(const QRectF &rect)
qreal width() const const
QPoint screenPos() const const
QGraphicsScene * scene() const const
void addLayout(QLayout *layout, int row, int column, Qt::Alignment alignment)
void addWidget(QWidget *widget, int fromRow, int fromColumn, int rowSpan, int columnSpan, Qt::Alignment alignment)
void setColumnStretch(int column, int stretch)
void setRowStretch(int row, int stretch)
virtual void setSpacing(int spacing) override
QIcon fromTheme(const QString &name)
void setSizeConstraint(SizeConstraint)
iterator begin()
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
iterator end()
T & first()
iterator insert(const_iterator before, parameter_type value)
bool isEmpty() const const
void prepend(parameter_type value)
QAction * addAction(const QIcon &icon, const QString &text, Functor functor, const QKeySequence &shortcut)
QAction * addSeparator()
QAction * exec()
StandardButton warning(QWidget *parent, const QString &title, const QString &text, StandardButtons buttons, StandardButton defaultButton)
QPoint pos() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
QObject * sender() const const
void setObjectName(QAnyStringView name)
QString tr(const char *sourceText, const char *disambiguation, int n)
int x() const const
int y() const const
Qt::MouseButton button() const const
int width() const const
QString arg(Args &&... args) const const
bool isEmpty() const const
QString number(double n, char format, int precision)
QString toLower() const const
CrossCursor
LeftButton
Horizontal
int toInt(bool *ok) const const
QString toString() const const
QList< QAction * > actions() const const
void adjustSize()
virtual bool event(QEvent *event) override
QLayout * layout() const const
void setMaximumSize(const QSize &)
void setMinimumSize(const QSize &)
void show()
void update()
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sat Apr 27 2024 22:16:56 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.