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?
61 const char ns[] = "http://kexi-project.org/report/2.0";
62
propertyToElement(QDomDocument * d,KProperty * p)63 static QDomElement propertyToElement(QDomDocument* d, KProperty* p)
64 {
65 QDomElement e = d->createElement(QLatin1String("report:" + p->name().toLower()));
66 e.appendChild(d->createTextNode(p->value().toString()));
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 //
74 class ReportWriterSectionData
75 {
76 public:
ReportWriterSectionData()77 ReportWriterSectionData() {
78 selected_x_offset = 0;
79 selected_y_offset = 0;
80 mouseAction = MouseAction::None;
81 }
~ReportWriterSectionData()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
107 QList<KReportDesignerItemBase*> copy_list;
108 QList<KReportDesignerItemBase*> cut_list;
109 };
110
111 //! @internal
112 class Q_DECL_HIDDEN KReportDesigner::Private
113 {
114 public:
115 explicit Private(KReportDesigner *designer);
116
~Private()117 ~Private()
118 {
119 delete dataSource;
120 }
121
122 void init(const QDomElement *xml);
123
updateCurrentUnit()124 void updateCurrentUnit() {
125 QString u = unit->value().toString();
126 KReportUnit newUnit = KReportUnit(KReportUnit::symbolToType(u));
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;
178 KProperty *pageSize;
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
221 private:
222 void loadXml(const QDomElement &data);
223 };
224
Private(KReportDesigner * designer)225 KReportDesigner::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)
init(const QDomElement * xml)231 void 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);
243 grid->setSizeConstraint(QLayout::SetFixedSize);
244
245 vboxlayout = new QVBoxLayout();
246 vboxlayout->setSpacing(0);
247 vboxlayout->setMargin(0);
248 vboxlayout->setSizeConstraint(QLayout::SetFixedSize);
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
268 connect(pageButton, &KReportPropertiesButton::released,
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
loadXml(const QDomElement & data)281 void 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(
341 KReportUnit::parseValue(it.toElement().attribute(
342 QLatin1String("fo:margin-right"), DEFAULT_PAGE_MARGIN_STRING))));
343 leftMargin->setValue(currentUnit.convertFromPoint(
344 KReportUnit::parseValue(it.toElement().attribute(
345 QLatin1String("fo:margin-left"), DEFAULT_PAGE_MARGIN_STRING))));
346 topMargin->setValue(currentUnit.convertFromPoint(
347 KReportUnit::parseValue(it.toElement().attribute(
348 QLatin1String("fo:margin-top"), DEFAULT_PAGE_MARGIN_STRING))));
349 bottomMargin->setValue(currentUnit.convertFromPoint(
350 KReportUnit::parseValue(it.toElement().attribute(
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")) {
371 KReportDesignerSectionDetail * rsd = new KReportDesignerSectionDetail(q);
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
updateScripts()391 void 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
KReportDesigner(QWidget * parent)403 KReportDesigner::KReportDesigner(QWidget * parent)
404 : QWidget(parent), d(new Private(this))
405 {
406 d->init(nullptr);
407 }
408
KReportDesigner(QWidget * parent,const QDomElement & data)409 KReportDesigner::KReportDesigner(QWidget *parent, const QDomElement &data)
410 : QWidget(parent), d(new Private(this))
411 {
412 d->init(&data);
413 }
414
~KReportDesigner()415 KReportDesigner::~KReportDesigner()
416 {
417 delete d;
418 }
419
420 ///The saving code
document() const421 QDomElement KReportDesigner::document() const
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
slotSectionEditor()527 void KReportDesigner::slotSectionEditor()
528 {
529 KReportSectionEditor se(this);
530 (void)se.exec();
531 }
532
setDataSource(KReportDataSource * source)533 void KReportDesigner::setDataSource(KReportDataSource* source)
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
setScriptSource(KReportScriptSource * source)547 void KReportDesigner::setScriptSource(KReportScriptSource* source)
548 {
549 d->scriptSource = source;
550 }
551 #endif
552
section(KReportSectionData::Type type) const553 KReportDesignerSection * KReportDesigner::section(KReportSectionData::Type type) const
554 {
555 KReportDesignerSection *sec;
556 switch (type) {
557 case KReportSectionData::Type::PageHeaderAny:
558 sec = d->pageHeaderAny;
559 break;
560 case KReportSectionData::Type::PageHeaderEven:
561 sec = d->pageHeaderEven;
562 break;
563 case KReportSectionData::Type::PageHeaderOdd:
564 sec = d->pageHeaderOdd;
565 break;
566 case KReportSectionData::Type::PageHeaderFirst:
567 sec = d->pageHeaderFirst;
568 break;
569 case KReportSectionData::Type::PageHeaderLast:
570 sec = d->pageHeaderLast;
571 break;
572 case KReportSectionData::Type::PageFooterAny:
573 sec = d->pageFooterAny;
574 break;
575 case KReportSectionData::Type::PageFooterEven:
576 sec = d->pageFooterEven;
577 break;
578 case KReportSectionData::Type::PageFooterOdd:
579 sec = d->pageFooterOdd;
580 break;
581 case KReportSectionData::Type::PageFooterFirst:
582 sec = d->pageFooterFirst;
583 break;
584 case KReportSectionData::Type::PageFooterLast:
585 sec = d->pageFooterLast;
586 break;
587 case KReportSectionData::Type::ReportHeader:
588 sec = d->reportHeader;
589 break;
590 case KReportSectionData::Type::ReportFooter:
591 sec = d->reportFooter;
592 break;
593 default:
594 sec = nullptr;
595 }
596 return sec;
597 }
598
createSection()599 KReportDesignerSection* KReportDesigner::createSection()
600 {
601 return new KReportDesignerSection(this, d->zoomHandler);
602 }
603
removeSection(KReportSectionData::Type type)604 void KReportDesigner::removeSection(KReportSectionData::Type type)
605 {
606 KReportDesignerSection* sec = section(type);
607 if (sec) {
608 delete sec;
609
610 switch (type) {
611 case KReportSectionData::Type::PageHeaderAny:
612 d->pageHeaderAny = nullptr;
613 break;
614 case KReportSectionData::Type::PageHeaderEven:
615 sec = d->pageHeaderEven = nullptr;
616 break;
617 case KReportSectionData::Type::PageHeaderOdd:
618 d->pageHeaderOdd = nullptr;
619 break;
620 case KReportSectionData::Type::PageHeaderFirst:
621 d->pageHeaderFirst = nullptr;
622 break;
623 case KReportSectionData::Type::PageHeaderLast:
624 d->pageHeaderLast = nullptr;
625 break;
626 case KReportSectionData::Type::PageFooterAny:
627 d->pageFooterAny = nullptr;
628 break;
629 case KReportSectionData::Type::PageFooterEven:
630 d->pageFooterEven = nullptr;
631 break;
632 case KReportSectionData::Type::PageFooterOdd:
633 d->pageFooterOdd = nullptr;
634 break;
635 case KReportSectionData::Type::PageFooterFirst:
636 d->pageFooterFirst = nullptr;
637 break;
638 case KReportSectionData::Type::PageFooterLast:
639 d->pageFooterLast = nullptr;
640 break;
641 case KReportSectionData::Type::ReportHeader:
642 d->reportHeader = nullptr;
643 break;
644 case KReportSectionData::Type::ReportFooter:
645 d->reportFooter = nullptr;
646 break;
647 default:
648 sec = nullptr;
649 }
650
651 setModified(true);
652 adjustSize();
653 }
654 }
655
insertSection(KReportSectionData::Type type)656 void KReportDesigner::insertSection(KReportSectionData::Type type)
657 {
658 KReportDesignerSection* sec = section(type);
659 if (!sec) {
660 int idx = 0;
661 for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
662 i <= static_cast<int>(type); ++i)
663 {
664 if (section(static_cast<KReportSectionData::Type>(i)))
665 idx++;
666 }
667 if (type > KReportSectionData::Type::ReportHeader)
668 idx++;
669 //kreportDebug() << idx;
670 KReportDesignerSection *rs = createSection();
671 d->vboxlayout->insertWidget(idx, rs);
672
673 switch (type) {
674 case KReportSectionData::Type::PageHeaderAny:
675 rs->setTitle(tr("Page Header (Any)"));
676 d->pageHeaderAny = rs;
677 break;
678 case KReportSectionData::Type::PageHeaderEven:
679 rs->setTitle(tr("Page Header (Even)"));
680 d->pageHeaderEven = rs;
681 break;
682 case KReportSectionData::Type::PageHeaderOdd:
683 rs->setTitle(tr("Page Header (Odd)"));
684 d->pageHeaderOdd = rs;
685 break;
686 case KReportSectionData::Type::PageHeaderFirst:
687 rs->setTitle(tr("Page Header (First)"));
688 d->pageHeaderFirst = rs;
689 break;
690 case KReportSectionData::Type::PageHeaderLast:
691 rs->setTitle(tr("Page Header (Last)"));
692 d->pageHeaderLast = rs;
693 break;
694 case KReportSectionData::Type::PageFooterAny:
695 rs->setTitle(tr("Page Footer (Any)"));
696 d->pageFooterAny = rs;
697 break;
698 case KReportSectionData::Type::PageFooterEven:
699 rs->setTitle(tr("Page Footer (Even)"));
700 d->pageFooterEven = rs;
701 break;
702 case KReportSectionData::Type::PageFooterOdd:
703 rs->setTitle(tr("Page Footer (Odd)"));
704 d->pageFooterOdd = rs;
705 break;
706 case KReportSectionData::Type::PageFooterFirst:
707 rs->setTitle(tr("Page Footer (First)"));
708 d->pageFooterFirst = rs;
709 break;
710 case KReportSectionData::Type::PageFooterLast:
711 rs->setTitle(tr("Page Footer (Last)"));
712 d->pageFooterLast = rs;
713 break;
714 case KReportSectionData::Type::ReportHeader:
715 rs->setTitle(tr("Report Header"));
716 d->reportHeader = rs;
717 break;
718 case KReportSectionData::Type::ReportFooter:
719 rs->setTitle(tr("Report Footer"));
720 d->reportFooter = rs;
721 break;
722 //These sections cannot be inserted this way
723 case KReportSectionData::Type::None:
724 case KReportSectionData::Type::GroupHeader:
725 case KReportSectionData::Type::GroupFooter:
726 case KReportSectionData::Type::Detail:
727 break;
728 }
729
730 rs->show();
731 setModified(true);
732 adjustSize();
733 emit pagePropertyChanged(d->set);
734 }
735 }
736
setReportTitle(const QString & str)737 void KReportDesigner::setReportTitle(const QString & str)
738 {
739 if (reportTitle() != str) {
740 d->title->setValue(str);
741 setModified(true);
742 }
743 }
744
propertySet() const745 KPropertySet* KReportDesigner::propertySet() const
746 {
747 return &d->set;
748 }
749
selectedItemPropertySet() const750 KPropertySet* KReportDesigner::selectedItemPropertySet() const
751 {
752 return d->itemSet;
753 }
754
reportDataSource() const755 KReportDataSource *KReportDesigner::reportDataSource() const
756 {
757 return d->dataSource;
758 }
759
detailSection() const760 KReportDesignerSectionDetail * KReportDesigner::detailSection() const
761 {
762 return d->detail;
763 }
764
reportTitle() const765 QString KReportDesigner::reportTitle() const
766 {
767 return d->title->value().toString();
768 }
769
isModified() const770 bool KReportDesigner::isModified() const
771 {
772 return d->modified;
773 }
774
setModified(bool modified)775 void KReportDesigner::setModified(bool modified)
776 {
777 d->modified = modified;
778
779 if (d->modified) {
780 emit dirty();
781 }
782 }
783
fieldNames() const784 QStringList KReportDesigner::fieldNames() const
785 {
786 QStringList qs;
787 qs << QString();
788 if (d->dataSource)
789 qs << d->dataSource->fieldNames();
790
791 return qs;
792 }
793
fieldKeys() const794 QStringList KReportDesigner::fieldKeys() const
795 {
796 QStringList qs;
797 qs << QString();
798 if (d->dataSource)
799 qs << d->dataSource->fieldKeys();
800
801 return qs;
802 }
803
createProperties()804 void KReportDesigner::createProperties()
805 {
806 KReportDesigner::addMetaProperties(&d->set,
807 tr("Report", "Main report element"), QLatin1String("kreport-report-element"));
808
809 connect(&d->set, SIGNAL(propertyChanged(KPropertySet&,KProperty&)),
810 this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&)));
811
812 d->title = new KProperty("title", QLatin1String("Report"), tr("Title"), tr("Report Title"));
813
814 KPropertyListData *listData = new KPropertyListData(KReportPageSize::pageFormatKeys(),
815 KReportPageSize::pageFormatNames());
816 QVariant defaultKey = KReportPageSize::pageSizeKey(KReportPageSize::defaultSize());
817 d->pageSize = new KProperty("page-size", listData, defaultKey, tr("Page Size"));
818
819 d->customPageSize = new KProperty("custom-page-size", DEFAULT_CUSTOM_PAGE_SIZE,
820 tr("Custom Page Size"), tr("Custom Page Size"), KProperty::SizeF);
821 d->customPageSize->setOption("suffix", d->currentUnit.symbol());
822
823 listData = new KPropertyListData({ QLatin1String("portrait"), QLatin1String("landscape") },
824 QVariantList{ tr("Portrait"), tr("Landscape") });
825 d->orientation = new KProperty("print-orientation", listData, QLatin1String("portrait"),
826 tr("Page Orientation"));
827
828 QList<KReportUnit::Type> types(KReportUnit::allTypes());
829 types.removeOne(KReportUnit::Type::Pixel);
830 listData = new KPropertyListData(KReportUnit::symbols(types), KReportUnit::descriptions(types));
831 d->unit = new KProperty("page-unit", listData, DEFAULT_UNIT_STRING, tr("Page Unit"));
832 d->showGrid = new KProperty("grid-visible", true, tr("Show Grid"));
833 d->gridSnap = new KProperty("grid-snap", true, tr("Snap to Grid"));
834 d->gridDivisions = new KProperty("grid-divisions", 4, tr("Grid Divisions"));
835 d->gridDivisions->setOption("min", 1);
836 d->gridDivisions->setOption("max", 10);
837
838
839 d->leftMargin = new KProperty("margin-left", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
840 tr("Left Margin"), tr("Left Margin"), KProperty::Double);
841 d->rightMargin = new KProperty("margin-right", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
842 tr("Right Margin"), tr("Right Margin"), KProperty::Double);
843 d->topMargin = new KProperty("margin-top", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
844 tr("Top Margin"), tr("Top Margin"), KProperty::Double);
845 d->bottomMargin = new KProperty("margin-bottom", pageUnit().convertFromPoint(KReportUnit::parseValue(DEFAULT_PAGE_MARGIN_STRING)),
846 tr("Bottom Margin"), tr("Bottom Margin"), KProperty::Double);
847 d->leftMargin->setOption("suffix", d->currentUnit.symbol());
848 d->rightMargin->setOption("suffix", d->currentUnit.symbol());
849 d->topMargin->setOption("suffix", d->currentUnit.symbol());
850 d->bottomMargin->setOption("suffix", d->currentUnit.symbol());
851
852 d->set.addProperty(d->title);
853 d->set.addProperty(d->pageSize);
854 d->set.addProperty(d->customPageSize);
855 d->set.addProperty(d->orientation);
856 d->set.addProperty(d->unit);
857 d->set.addProperty(d->gridSnap);
858 d->set.addProperty(d->showGrid);
859 d->set.addProperty(d->gridDivisions);
860 d->set.addProperty(d->leftMargin);
861 d->set.addProperty(d->rightMargin);
862 d->set.addProperty(d->topMargin);
863 d->set.addProperty(d->bottomMargin);
864
865 recalculateMaxMargins();
866
867 #ifdef KREPORT_SCRIPTING
868 d->script = new KProperty("script", new KPropertyListData, QVariant(), tr("Object Script"));
869 d->set.addProperty(d->script);
870 #endif
871 }
872
873 /**
874 @brief Handle property changes
875 */
slotPropertyChanged(KPropertySet & s,KProperty & p)876 void KReportDesigner::slotPropertyChanged(KPropertySet &s, KProperty &p)
877 {
878 const QSignalBlocker blocker(s);
879 setModified(true);
880 QByteArray propertyName = p.name();
881
882 if (propertyName == "page-unit") {
883 const KReportUnit oldUnit = d->currentUnit;
884 d->updateCurrentUnit();
885 d->hruler->setUnit(pageUnit());
886
887 // convert values
888 d->leftMargin->setValue(KReportUnit::convertFromUnitToUnit(
889 d->leftMargin->value().toDouble(), oldUnit, d->currentUnit),
890 KProperty::ValueOption::IgnoreOld);
891
892 d->rightMargin->setValue(KReportUnit::convertFromUnitToUnit(
893 d->rightMargin->value().toDouble(), oldUnit, d->currentUnit),
894 KProperty::ValueOption::IgnoreOld);
895
896 d->topMargin->setValue(KReportUnit::convertFromUnitToUnit(d->topMargin->value().toDouble(),
897 oldUnit, d->currentUnit),
898 KProperty::ValueOption::IgnoreOld);
899
900 d->bottomMargin->setValue(KReportUnit::convertFromUnitToUnit(
901 d->bottomMargin->value().toDouble(), oldUnit, d->currentUnit),
902 KProperty::ValueOption::IgnoreOld);
903
904 d->customPageSize->setValue(
905 KReportUnit::convertFromUnitToUnit(d->customPageSize->value().toSizeF(), oldUnit,
906 d->currentUnit),
907 KProperty::ValueOption::IgnoreOld);
908
909 d->leftMargin->setOption("suffix", d->currentUnit.symbol());
910 d->rightMargin->setOption("suffix", d->currentUnit.symbol());
911 d->topMargin->setOption("suffix", d->currentUnit.symbol());
912 d->bottomMargin->setOption("suffix", d->currentUnit.symbol());
913 d->customPageSize->setOption("suffix", d->currentUnit.symbol());
914 } else if (propertyName.startsWith("margin-") || propertyName == "page-size" || propertyName == "custom-page-size") {
915 recalculateMaxMargins();
916 }
917 emit pagePropertyChanged(s);
918
919 }
920
slotPageButton_Pressed()921 void KReportDesigner::slotPageButton_Pressed()
922 {
923 #ifdef KREPORT_SCRIPTING
924 d->updateScripts();
925 changeSet(&d->set);
926 #endif
927 }
928
sizeHint() const929 QSize KReportDesigner::sizeHint() const
930 {
931 int w = 0;
932 int h = 0;
933
934 if (d->pageFooterAny)
935 h += d->pageFooterAny->sizeHint().height();
936 if (d->pageFooterEven)
937 h += d->pageFooterEven->sizeHint().height();
938 if (d->pageFooterFirst)
939 h += d->pageFooterFirst->sizeHint().height();
940 if (d->pageFooterLast)
941 h += d->pageFooterLast->sizeHint().height();
942 if (d->pageFooterOdd)
943 h += d->pageFooterOdd->sizeHint().height();
944 if (d->pageHeaderAny)
945 h += d->pageHeaderAny->sizeHint().height();
946 if (d->pageHeaderEven)
947 h += d->pageHeaderEven->sizeHint().height();
948 if (d->pageHeaderFirst)
949 h += d->pageHeaderFirst->sizeHint().height();
950 if (d->pageHeaderLast)
951 h += d->pageHeaderLast->sizeHint().height();
952 if (d->pageHeaderOdd)
953 h += d->pageHeaderOdd->sizeHint().height();
954 if (d->reportHeader)
955 h += d->reportHeader->sizeHint().height();
956 if (d->reportFooter) {
957 h += d->reportFooter->sizeHint().height();
958
959 }
960 if (d->detail) {
961 h += d->detail->sizeHint().height();
962 w += d->detail->sizeHint().width();
963 }
964
965 h += d->hruler->height();
966
967 return QSize(w, h);
968 }
969
pageWidthPx() const970 int KReportDesigner::pageWidthPx() const
971 {
972 QSize pageSizePx;
973 int pageWidth;
974
975 if (d->set.property("page-size").value().toString() == QLatin1String("Custom")) {
976 KReportUnit unit = pageUnit();
977
978 QSizeF customSize = d->currentUnit.convertToPoint(d->set.property("custom-page-size").value().toSizeF());
979 QPageLayout layout(QPageSize(customSize, QPageSize::Point, QString(), QPageSize::ExactMatch), d->set.property("print-orientation").value().toString()
980 == QLatin1String("portrait") ? QPageLayout::Portrait : QPageLayout::Landscape, QMarginsF(0,0,0,0));
981
982 pageSizePx = layout.fullRectPixels(KReportPrivate::dpiX()).size();
983 } else {
984 QPageLayout layout = QPageLayout(
985 QPageSize(KReportPageSize::pageSize(d->set.property("page-size").value().toString())),
986 d->set.property("print-orientation").value().toString()
987 == QLatin1String("portrait") ? QPageLayout::Portrait : QPageLayout::Landscape, QMarginsF(0,0,0,0));
988 pageSizePx = layout.fullRectPixels(KReportPrivate::dpiX()).size();
989 }
990
991 pageWidth = pageSizePx.width();
992
993 pageWidth = pageWidth - KReportUnit::convertFromUnitToUnit(d->set.property("margin-left").value().toDouble(), pageUnit(), KReportUnit(KReportUnit::Type::Inch)) * KReportPrivate::dpiX();
994 pageWidth = pageWidth - KReportUnit::convertFromUnitToUnit(d->set.property("margin-right").value().toDouble(), pageUnit(), KReportUnit(KReportUnit::Type::Inch)) * KReportPrivate::dpiX();
995
996 return pageWidth;
997 }
998
pageSizePt() const999 QSize KReportDesigner::pageSizePt() const
1000 {
1001 QSize pageSizePt;
1002
1003 if (d->set.property("page-size").value().toString() == QLatin1String("Custom")) {
1004 KReportUnit unit = pageUnit();
1005
1006 QSizeF customSize = d->currentUnit.convertToPoint(d->set.property("custom-page-size").value().toSizeF());
1007 QPageLayout layout(QPageSize(customSize, QPageSize::Point, QString(), QPageSize::ExactMatch), d->set.property("print-orientation").value().toString()
1008 == QLatin1String("portrait") ? QPageLayout::Portrait : QPageLayout::Landscape, QMarginsF(0,0,0,0));
1009
1010 pageSizePt = layout.fullRectPoints().size();
1011 } else {
1012 QPageLayout layout = QPageLayout(
1013 QPageSize(KReportPageSize::pageSize(d->set.property("page-size").value().toString())),
1014 d->set.property("print-orientation").value().toString()
1015 == QLatin1String("portrait") ? QPageLayout::Portrait : QPageLayout::Landscape, QMarginsF(0,0,0,0));
1016 pageSizePt = layout.fullRectPoints().size();
1017 }
1018
1019 return pageSizePt;
1020 }
1021
resizeEvent(QResizeEvent * event)1022 void KReportDesigner::resizeEvent(QResizeEvent * event)
1023 {
1024 Q_UNUSED(event);
1025 d->hruler->setRulerLength(pageWidthPx());
1026 }
1027
setDetail(KReportDesignerSectionDetail * rsd)1028 void KReportDesigner::setDetail(KReportDesignerSectionDetail *rsd)
1029 {
1030 if (!d->detail) {
1031 int idx = 0;
1032 if (d->pageHeaderFirst) idx++;
1033 if (d->pageHeaderOdd) idx++;
1034 if (d->pageHeaderEven) idx++;
1035 if (d->pageHeaderLast) idx++;
1036 if (d->pageHeaderAny) idx++;
1037 if (d->reportHeader) idx++;
1038 d->detail = rsd;
1039 d->vboxlayout->insertWidget(idx, d->detail);
1040 }
1041 }
1042
pageUnit() const1043 KReportUnit KReportDesigner::pageUnit() const
1044 {
1045 return d->currentUnit;
1046 }
1047
setGridOptions(bool vis,int div)1048 void KReportDesigner::setGridOptions(bool vis, int div)
1049 {
1050 d->showGrid->setValue(QVariant(vis));
1051 d->gridDivisions->setValue(div);
1052 }
1053
1054 //
1055 // methods for the sectionMouse*Event()
1056 //
sectionContextMenuEvent(KReportDesignerSectionScene * s,QGraphicsSceneContextMenuEvent * e)1057 void KReportDesigner::sectionContextMenuEvent(KReportDesignerSectionScene * s, QGraphicsSceneContextMenuEvent * e)
1058 {
1059 Q_UNUSED(s);
1060
1061 QMenu pop;
1062
1063 bool itemsSelected = selectionCount() > 0;
1064 if (itemsSelected) {
1065 //! @todo KF5 use KStandardAction
1066 QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-cut")), tr("Cut"), this);
1067 connect(a, SIGNAL(triggered()), this, SLOT(slotEditCut()));
1068 pop.addAction(a);
1069 //! @todo KF5 use KStandardAction
1070 a = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), tr("Copy"), this);
1071 connect(a, SIGNAL(triggered()), this, SLOT(slotEditCopy()));
1072 pop.addAction(a);
1073 }
1074 if (!d->sectionData.copy_list.isEmpty()) {
1075 QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-paste")), tr("Paste"), this);
1076 connect(a, SIGNAL(triggered()), this, SLOT(slotEditPaste()));
1077 pop.addAction(a);
1078 }
1079
1080 if (itemsSelected) {
1081 pop.addSeparator();
1082 //! @todo KF5 use KStandard*
1083 //const KGuiItem del = KStandardGuiItem::del();
1084 //a->setToolTip(del.toolTip());
1085 //a->setShortcut(QKeySequence(QKeySequence::Delete));
1086 QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), tr("Delete"), this);
1087 connect(a, SIGNAL(triggered()), SLOT(slotEditDelete()));
1088 pop.addAction(a);
1089 }
1090 if (!pop.actions().isEmpty()) {
1091 pop.exec(e->screenPos());
1092 }
1093 }
1094
sectionMousePressEvent(KReportDesignerSectionView * v,QMouseEvent * e)1095 void KReportDesigner::sectionMousePressEvent(KReportDesignerSectionView * v, QMouseEvent * e)
1096 {
1097 Q_UNUSED(v);
1098 d->pressX = e->pos().x();
1099 d->pressY = e->pos().y();
1100 }
1101
sectionMouseReleaseEvent(KReportDesignerSectionView * v,QMouseEvent * e)1102 void KReportDesigner::sectionMouseReleaseEvent(KReportDesignerSectionView * v, QMouseEvent * e)
1103 {
1104 e->accept();
1105
1106 d->releaseX = e->pos().x();
1107 d->releaseY = e->pos().y();
1108
1109 if (e->button() == Qt::LeftButton) {
1110 QPointF pos(d->pressX, d->pressY);
1111 QPointF end(d->releaseX, d->releaseY);
1112 if (d->releaseY >= v->scene()->height()) {
1113 d->releaseY = v->scene()->height();
1114 end.setY(v->scene()->height());
1115 }
1116
1117 if (d->releaseX >= v->scene()->width()) {
1118 d->releaseX = v->scene()->width();
1119 end.setX(v->scene()->width());
1120 }
1121
1122 if (d->sectionData.mouseAction == ReportWriterSectionData::MouseAction::Insert) {
1123 QGraphicsItem * item = nullptr;
1124 QString classString;
1125 QString iconName;
1126 if (d->sectionData.itemToInsert == QLatin1String("org.kde.kreport.line")) {
1127 item = new KReportDesignerItemLine(v->designer(), v->scene(), pos, end);
1128 classString = tr("Line", "Report line element");
1129 iconName = QLatin1String("kreport-line-element");
1130 }
1131 else {
1132 KReportPluginManager* pluginManager = KReportPluginManager::self();
1133 KReportPluginInterface *plug = pluginManager->plugin(d->sectionData.itemToInsert);
1134 if (plug) {
1135 QObject *obj = plug->createDesignerInstance(v->designer(), v->scene(), pos);
1136 if (obj) {
1137 item = dynamic_cast<QGraphicsItem*>(obj);
1138 classString = plug->metaData()->name();
1139 iconName = plug->metaData()->iconName();
1140 }
1141 }
1142 else {
1143 kreportWarning() << "attempted to insert an unknown item";
1144 }
1145 }
1146 if (item) {
1147 item->setVisible(true);
1148 item->setSelected(true);
1149 KReportItemBase* baseReportItem = dynamic_cast<KReportItemBase*>(item);
1150 if (baseReportItem) {
1151 KPropertySet *set = baseReportItem->propertySet();
1152 KReportDesigner::addMetaProperties(set, classString, iconName);
1153 set->clearModifiedFlags();
1154 changeSet(set);
1155 if (v && v->designer()) {
1156 v->designer()->setModified(true);
1157 }
1158 emit itemInserted(d->sectionData.itemToInsert);
1159 }
1160 }
1161
1162 d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::None;
1163 d->sectionData.itemToInsert.clear();
1164 unsetSectionCursor();
1165 }
1166 }
1167 }
1168
selectionCount() const1169 unsigned int KReportDesigner::selectionCount() const
1170 {
1171 if (activeScene())
1172 return activeScene()->selectedItems().count();
1173 else
1174 return 0;
1175 }
1176
changeSet(KPropertySet * set)1177 void KReportDesigner::changeSet(KPropertySet *set)
1178 {
1179 //Set the checked state of the report properties button
1180 if (set == &d->set)
1181 d->pageButton->setCheckState(Qt::Checked);
1182 else
1183 d->pageButton->setCheckState(Qt::Unchecked);
1184
1185 if (d->itemSet != set) {
1186 d->itemSet = set;
1187 emit propertySetChanged();
1188 }
1189 }
1190
1191 //
1192 // Actions
1193 //
1194
slotItem(const QString & entity)1195 void KReportDesigner::slotItem(const QString &entity)
1196 {
1197 //kreportDebug() << entity;
1198 d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::Insert;
1199 d->sectionData.itemToInsert = entity;
1200 setSectionCursor(QCursor(Qt::CrossCursor));
1201 }
1202
slotEditDelete()1203 void KReportDesigner::slotEditDelete()
1204 {
1205 QGraphicsItem * item = nullptr;
1206 bool modified = false;
1207 while (selectionCount() > 0) {
1208 item = activeScene()->selectedItems().value(0);
1209 if (item) {
1210 QGraphicsScene * scene = item->scene();
1211 delete item;
1212 scene->update();
1213 d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::None;
1214 modified = true;
1215 }
1216 }
1217 activeScene()->selectedItems().clear();
1218
1219 /*! @todo temporary: clears cut and copy lists to make sure we do not crash
1220 if weve deleted something in the list
1221 should really check if an item is in the list first
1222 and remove it. */
1223 d->sectionData.cut_list.clear();
1224 d->sectionData.copy_list.clear();
1225 if (modified) {
1226 setModified(true);
1227 }
1228 }
1229
slotEditCut()1230 void KReportDesigner::slotEditCut()
1231 {
1232 if (selectionCount() > 0) {
1233 //First delete any items that are curerntly in the list
1234 //so as not to leak memory
1235 qDeleteAll(d->sectionData.cut_list);
1236 d->sectionData.cut_list.clear();
1237
1238 QGraphicsItem * item = activeScene()->selectedItems().first();
1239 bool modified = false;
1240 if (item) {
1241 d->sectionData.copy_list.clear();
1242 foreach(QGraphicsItem *item, activeScene()->selectedItems()) {
1243 d->sectionData.cut_list.append(dynamic_cast<KReportDesignerItemBase*>(item));
1244 d->sectionData.copy_list.append(dynamic_cast<KReportDesignerItemBase*>(item));
1245 }
1246 foreach(QGraphicsItem *item, activeScene()->selectedItems()) {
1247 activeScene()->removeItem(item);
1248 activeScene()->update();
1249 modified = true;
1250 }
1251 d->sectionData.selected_x_offset = 10;
1252 d->sectionData.selected_y_offset = 10;
1253 }
1254 if (modified) {
1255 setModified(true);
1256 }
1257 }
1258 }
1259
slotEditCopy()1260 void KReportDesigner::slotEditCopy()
1261 {
1262 if (selectionCount() < 1)
1263 return;
1264
1265 QGraphicsItem * item = activeScene()->selectedItems().first();
1266 if (item) {
1267 d->sectionData.copy_list.clear();
1268 foreach(QGraphicsItem *item, activeScene()->selectedItems()) {
1269 d->sectionData.copy_list.append(dynamic_cast<KReportDesignerItemBase*>(item));
1270 }
1271 d->sectionData.selected_x_offset = 10;
1272 d->sectionData.selected_y_offset = 10;
1273 }
1274 }
1275
slotEditPaste()1276 void KReportDesigner::slotEditPaste()
1277 {
1278 // call the editPaste function passing it a reportsection
1279 slotEditPaste(activeScene());
1280 }
1281
slotEditPaste(QGraphicsScene * canvas)1282 void KReportDesigner::slotEditPaste(QGraphicsScene * canvas)
1283 {
1284
1285 // paste a new item of the copy we have in the specified location
1286 if (!d->sectionData.copy_list.isEmpty()) {
1287 QList<QGraphicsItem*> activeItems = canvas->selectedItems();
1288 QGraphicsItem *activeItem = nullptr;
1289 if (activeItems.count() == 1) {
1290 activeItem = activeItems.first();
1291 }
1292 canvas->clearSelection();
1293 d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::None;
1294
1295 //! @todo this code sucks :)
1296 //! The setPos calls only work AFTER the name has been set ?!?!?
1297
1298 foreach(KReportDesignerItemBase *item, d->sectionData.copy_list) {
1299 KReportItemBase *obj = dynamic_cast<KReportItemBase*>(item);
1300 const QString type = obj ? obj->typeName() : QLatin1String("object");
1301 //kreportDebug() << type;
1302 KReportDesignerItemBase *ent = item->clone();
1303 KReportItemBase *new_obj = dynamic_cast<KReportItemBase*>(ent);
1304 if (new_obj) {
1305 new_obj->setEntityName(suggestEntityName(type));
1306 if (activeItem) {
1307 new_obj->setPosition(KReportItemBase::positionFromScene(QPointF(activeItem->x() + 10, activeItem->y() + 10)));
1308 } else {
1309 new_obj->setPosition(KReportItemBase::positionFromScene(QPointF(0, 0)));
1310 }
1311 new_obj->propertySet()->clearModifiedFlags();
1312 changeSet(new_obj->propertySet());
1313 }
1314 QGraphicsItem *pasted_ent = dynamic_cast<QGraphicsItem*>(ent);
1315 if (pasted_ent) {
1316 pasted_ent->setSelected(true);
1317 canvas->addItem(pasted_ent);
1318 pasted_ent->show();
1319 d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::Grab;
1320 setModified(true);
1321 }
1322 }
1323 }
1324 }
slotRaiseSelected()1325 void KReportDesigner::slotRaiseSelected()
1326 {
1327 dynamic_cast<KReportDesignerSectionScene*>(activeScene())->raiseSelected();
1328 }
1329
slotLowerSelected()1330 void KReportDesigner::slotLowerSelected()
1331 {
1332 dynamic_cast<KReportDesignerSectionScene*>(activeScene())->lowerSelected();
1333 }
1334
activeScene() const1335 QGraphicsScene* KReportDesigner::activeScene() const
1336 {
1337 return d->activeScene;
1338 }
1339
setActiveScene(QGraphicsScene * a)1340 void KReportDesigner::setActiveScene(QGraphicsScene* a)
1341 {
1342 if (d->activeScene && d->activeScene != a)
1343 d->activeScene->clearSelection();
1344 d->activeScene = a;
1345
1346 //Trigger an update so that the last scene redraws its title;
1347 update();
1348 }
1349
suggestEntityName(const QString & name) const1350 QString KReportDesigner::suggestEntityName(const QString &name) const
1351 {
1352 KReportDesignerSection *sec;
1353 int itemCount = 0;
1354 // Count items in the main sections
1355 for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
1356 i <= static_cast<int>(KReportSectionData::Type::PageFooterAny); i++)
1357 {
1358 sec = section(static_cast<KReportSectionData::Type>(i));
1359 if (sec) {
1360 const QGraphicsItemList l = sec->items();
1361 itemCount += l.count();
1362 }
1363 }
1364
1365 if (d->detail) {
1366 //Count items in the group headers/footers
1367 for (int i = 0; i < d->detail->groupSectionCount(); i++) {
1368 sec = d->detail->groupSection(i)->groupHeader();
1369 if (sec) {
1370 const QGraphicsItemList l = sec->items();
1371 itemCount += l.count();
1372 }
1373 sec = d->detail->groupSection(i)->groupFooter();
1374 if (sec) {
1375 const QGraphicsItemList l = sec->items();
1376 itemCount += l.count();
1377 }
1378 }
1379
1380 sec = d->detail->detailSection();
1381 if (sec) {
1382 const QGraphicsItemList l = sec->items();
1383 itemCount += l.count();
1384 }
1385 }
1386
1387 while (!isEntityNameUnique(name + QString::number(itemCount))) {
1388 itemCount++;
1389 }
1390 return name + QString::number(itemCount);
1391 }
1392
isEntityNameUnique(const QString & name,KReportItemBase * ignore) const1393 bool KReportDesigner::isEntityNameUnique(const QString &name, KReportItemBase* ignore) const
1394 {
1395 KReportDesignerSection *sec;
1396 bool unique = true;
1397
1398 // Check items in the main sections
1399 for (int i = static_cast<int>(KReportSectionData::Type::PageHeaderFirst);
1400 i <= static_cast<int>(KReportSectionData::Type::PageFooterAny); i++)
1401 {
1402 sec = section(static_cast<KReportSectionData::Type>(i));
1403 if (sec) {
1404 const QGraphicsItemList l = sec->items();
1405 for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) {
1406 KReportItemBase* itm = dynamic_cast<KReportItemBase*>(*it);
1407 if (itm && itm->entityName() == name && itm != ignore) {
1408 unique = false;
1409 break;
1410 }
1411 }
1412 if (!unique) break;
1413 }
1414 }
1415
1416 //Count items in the group headers/footers
1417 if (unique && d->detail) {
1418 for (int i = 0; i < d->detail->groupSectionCount(); ++i) {
1419 sec = d->detail->groupSection(i)->groupHeader();
1420 if (sec) {
1421 const QGraphicsItemList l = sec->items();
1422 for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) {
1423 KReportItemBase* itm = dynamic_cast<KReportItemBase*>(*it);
1424 if (itm && itm->entityName() == name && itm != ignore) {
1425 unique = false;
1426 break;
1427 }
1428 }
1429
1430 }
1431 sec = d->detail->groupSection(i)->groupFooter();
1432 if (unique && sec) {
1433 const QGraphicsItemList l = sec->items();
1434 for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) {
1435 KReportItemBase* itm = dynamic_cast<KReportItemBase*>(*it);
1436 if (itm && itm->entityName() == name && itm != ignore) {
1437 unique = false;
1438 break;
1439 }
1440 }
1441 }
1442 }
1443 }
1444 if (unique && d->detail) {
1445 sec = d->detail->detailSection();
1446 if (sec) {
1447 const QGraphicsItemList l = sec->items();
1448 for (QGraphicsItemList::const_iterator it = l.constBegin(); it != l.constEnd(); ++it) {
1449 KReportItemBase* itm = dynamic_cast<KReportItemBase*>(*it);
1450 if (itm && itm->entityName() == name && itm != ignore) {
1451 unique = false;
1452 break;
1453 }
1454 }
1455 }
1456 }
1457
1458 return unique;
1459 }
1460
actionPriortyLessThan(QAction * act1,QAction * act2)1461 static bool actionPriortyLessThan(QAction* act1, QAction* act2)
1462 {
1463 if (act1->data().toInt() > 0 && act2->data().toInt() > 0) {
1464 return act1->data().toInt() < act2->data().toInt();
1465 }
1466 return false;
1467 }
1468
itemActions(QActionGroup * group)1469 QList<QAction*> KReportDesigner::itemActions(QActionGroup* group)
1470 {
1471 KReportPluginManager* manager = KReportPluginManager::self();
1472 QList<QAction*> actList = manager->createActions(group);
1473
1474 //! @todo make line a real plugin so this isn't needed:
1475 QAction *act = new QAction(QIcon::fromTheme(QLatin1String("kreport-line-element")), tr("Line"), group);
1476 act->setObjectName(QLatin1String("org.kde.kreport.line"));
1477 act->setData(9);
1478 act->setCheckable(true);
1479 actList << act;
1480
1481 qSort(actList.begin(), actList.end(), actionPriortyLessThan);
1482 int i = 0;
1483
1484 /*! @todo maybe this is a bit hackish
1485 It finds the first plugin based on the priority in userdata
1486 The lowest oriority a plugin can have is 10
1487 And inserts a separator before it. */
1488 bool sepInserted = false;
1489 foreach(QAction *a, actList) {
1490 ++i;
1491 if (!sepInserted && a->data().toInt() >= 10) {
1492 QAction *sep = new QAction(QLatin1String("separator"), group);
1493 sep->setSeparator(true);
1494 actList.insert(i-1, sep);
1495 sepInserted = true;
1496 }
1497 if (group) {
1498 group->addAction(a);
1499 }
1500 }
1501
1502 return actList;
1503 }
1504
designerActions()1505 QList< QAction* > KReportDesigner::designerActions()
1506 {
1507 QList<QAction*> al;
1508 QAction *sep = new QAction(QString(), this);
1509 sep->setSeparator(true);
1510
1511 al << d->editCutAction << d->editCopyAction << d->editPasteAction << d->editDeleteAction << sep << d->sectionEdit << sep << d->itemLowerAction << d->itemRaiseAction;
1512
1513 return al;
1514 }
1515
createActions()1516 void KReportDesigner::createActions()
1517 {
1518 d->editCutAction = new QAction(QIcon::fromTheme(QLatin1String("edit-cut")), tr("Cu&t"), this);
1519 d->editCutAction->setObjectName(QLatin1String("edit_cut"));
1520 d->editCutAction->setToolTip(tr("Cut selection to clipboard"));
1521 d->editCutAction->setShortcuts(KStandardShortcut::cut());
1522 d->editCutAction->setProperty("iconOnly", true);
1523
1524 d->editCopyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), tr("&Copy"), this);
1525 d->editCopyAction->setObjectName(QLatin1String("edit_copy"));
1526 d->editCopyAction->setToolTip(tr("Copy selection to clipboard"));
1527 d->editCopyAction->setShortcuts(KStandardShortcut::copy());
1528 d->editCopyAction->setProperty("iconOnly", true);
1529
1530 d->editPasteAction = new QAction(QIcon::fromTheme(QLatin1String("edit-paste")), tr("&Paste"), this);
1531 d->editPasteAction->setObjectName(QLatin1String("edit_paste"));
1532 d->editPasteAction->setToolTip(tr("Paste clipboard content"));
1533 d->editPasteAction->setShortcuts(KStandardShortcut::paste());
1534 d->editPasteAction->setProperty("iconOnly", true);
1535
1536 const KGuiItem del = KStandardGuiItem::del();
1537 d->editDeleteAction = new QAction(del.icon(), del.text(), this);
1538 d->editDeleteAction->setObjectName(QLatin1String("edit_delete"));
1539 d->editDeleteAction->setToolTip(del.toolTip());
1540 d->editDeleteAction->setWhatsThis(del.whatsThis());
1541 d->editDeleteAction->setProperty("iconOnly", true);
1542
1543 d->sectionEdit = new QAction(tr("Edit Sections"), this);
1544 d->sectionEdit->setObjectName(QLatin1String("section_edit"));
1545
1546 d->itemRaiseAction = new QAction(QIcon::fromTheme(QLatin1String("arrow-up")), tr("Raise"), this);
1547 d->itemRaiseAction->setObjectName(QLatin1String("item_raise"));
1548 d->itemLowerAction = new QAction(QIcon::fromTheme(QLatin1String("arrow-down")), tr("Lower"), this);
1549 d->itemLowerAction->setObjectName(QLatin1String("item_lower"));
1550
1551 //Edit Actions
1552 connect(d->editCutAction, SIGNAL(triggered(bool)), this, SLOT(slotEditCut()));
1553 connect(d->editCopyAction, SIGNAL(triggered(bool)), this, SLOT(slotEditCopy()));
1554 connect(d->editPasteAction, SIGNAL(triggered(bool)), this, SLOT(slotEditPaste()));
1555 connect(d->editDeleteAction, SIGNAL(triggered(bool)), this, SLOT(slotEditDelete()));
1556
1557 connect(d->sectionEdit, SIGNAL(triggered(bool)), this, SLOT(slotSectionEditor()));
1558
1559 //Raise/Lower
1560 connect(d->itemRaiseAction, SIGNAL(triggered(bool)), this, SLOT(slotRaiseSelected()));
1561 connect(d->itemLowerAction, SIGNAL(triggered(bool)), this, SLOT(slotLowerSelected()));
1562 }
1563
setSectionCursor(const QCursor & c)1564 void KReportDesigner::setSectionCursor(const QCursor& c)
1565 {
1566 if (d->pageFooterAny)
1567 d->pageFooterAny->setSectionCursor(c);
1568 if (d->pageFooterEven)
1569 d->pageFooterEven->setSectionCursor(c);
1570 if (d->pageFooterFirst)
1571 d->pageFooterFirst->setSectionCursor(c);
1572 if (d->pageFooterLast)
1573 d->pageFooterLast->setSectionCursor(c);
1574 if (d->pageFooterOdd)
1575 d->pageFooterOdd->setSectionCursor(c);
1576
1577 if (d->pageHeaderAny)
1578 d->pageHeaderAny->setSectionCursor(c);
1579 if (d->pageHeaderEven)
1580 d->pageHeaderEven->setSectionCursor(c);
1581 if (d->pageHeaderFirst)
1582 d->pageHeaderFirst->setSectionCursor(c);
1583 if (d->pageHeaderLast)
1584 d->pageHeaderLast->setSectionCursor(c);
1585 if (d->pageHeaderOdd)
1586 d->pageHeaderOdd->setSectionCursor(c);
1587
1588 if (d->detail)
1589 d->detail->setSectionCursor(c);
1590 }
1591
unsetSectionCursor()1592 void KReportDesigner::unsetSectionCursor()
1593 {
1594 if (d->pageFooterAny)
1595 d->pageFooterAny->unsetSectionCursor();
1596 if (d->pageFooterEven)
1597 d->pageFooterEven->unsetSectionCursor();
1598 if (d->pageFooterFirst)
1599 d->pageFooterFirst->unsetSectionCursor();
1600 if (d->pageFooterLast)
1601 d->pageFooterLast->unsetSectionCursor();
1602 if (d->pageFooterOdd)
1603 d->pageFooterOdd->unsetSectionCursor();
1604
1605 if (d->pageHeaderAny)
1606 d->pageHeaderAny->unsetSectionCursor();
1607 if (d->pageHeaderEven)
1608 d->pageHeaderEven->unsetSectionCursor();
1609 if (d->pageHeaderFirst)
1610 d->pageHeaderFirst->unsetSectionCursor();
1611 if (d->pageHeaderLast)
1612 d->pageHeaderLast->unsetSectionCursor();
1613 if (d->pageHeaderOdd)
1614 d->pageHeaderOdd->unsetSectionCursor();
1615
1616 if (d->detail)
1617 d->detail->unsetSectionCursor();
1618 }
1619
countSelectionHeight() const1620 qreal KReportDesigner::countSelectionHeight() const
1621 {
1622 if (d->releaseY == -1 || d->pressY == -1) {
1623 return -1;
1624 }
1625 return qAbs(d->releaseY - d->pressY);
1626 }
1627
countSelectionWidth() const1628 qreal KReportDesigner::countSelectionWidth() const
1629 {
1630 if (d->releaseX == -1 || d->pressX == -1) {
1631 return -1;
1632 }
1633 return qAbs(d->releaseX - d->pressX);
1634 }
1635
getSelectionPressX() const1636 qreal KReportDesigner::getSelectionPressX() const
1637 {
1638 return d->pressX;
1639 }
1640
getSelectionPressY() const1641 qreal KReportDesigner::getSelectionPressY() const
1642 {
1643 return d->pressY;
1644 }
1645
getPressPoint() const1646 QPointF KReportDesigner::getPressPoint() const
1647 {
1648 return QPointF(d->pressX, d->pressY);
1649 }
1650
getReleasePoint() const1651 QPointF KReportDesigner::getReleasePoint() const
1652 {
1653 return QPointF(d->releaseX, d->releaseY);
1654 }
1655
plugItemActions(const QList<QAction * > & actList)1656 void KReportDesigner::plugItemActions(const QList<QAction*> &actList)
1657 {
1658 foreach(QAction *a, actList) {
1659 connect(a, SIGNAL(triggered(bool)), this, SLOT(slotItemTriggered(bool)));
1660 }
1661 }
1662
slotItemTriggered(bool checked)1663 void KReportDesigner::slotItemTriggered(bool checked)
1664 {
1665 if (!checked) {
1666 return;
1667 }
1668 QObject *theSender = sender();
1669 if (!theSender) {
1670 return;
1671 }
1672 slotItem(theSender->objectName());
1673 }
1674
addMetaProperties(KPropertySet * set,const QString & classString,const QString & iconName)1675 void KReportDesigner::addMetaProperties(KPropertySet* set, const QString &classString,
1676 const QString &iconName)
1677 {
1678 Q_ASSERT(set);
1679 KProperty *prop;
1680 set->addProperty(prop = new KProperty("this:classString", classString));
1681 prop->setVisible(false);
1682 set->addProperty(prop = new KProperty("this:iconName", iconName));
1683 prop->setVisible(false);
1684 }
1685
recalculateMaxMargins()1686 void KReportDesigner::recalculateMaxMargins()
1687 {
1688 QSize pageSize = pageSizePt();
1689 d->leftMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.width() - d->currentUnit.convertToPoint(d->rightMargin->value().toReal()) - SMALLEST_PAGE_SIZE_PT));
1690 d->rightMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.width() - d->currentUnit.convertToPoint(d->leftMargin->value().toReal())- SMALLEST_PAGE_SIZE_PT));
1691 d->topMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.height() - d->currentUnit.convertToPoint(d->bottomMargin->value().toReal())- SMALLEST_PAGE_SIZE_PT));
1692 d->bottomMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.height() - d->currentUnit.convertToPoint(d->topMargin->value().toReal())- SMALLEST_PAGE_SIZE_PT));
1693 }
1694