KReport

KReportDesigner.cpp
1 /* This file is part of the KDE project
2  * Copyright (C) 2001-2007 by OpenMFG, LLC <[email protected]>
3  * Copyright (C) 2007-2010 by Adam Pigg <[email protected]>
4  * Copyright (C) 2011-2017 JarosÅ‚aw Staniek <[email protected]>
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 
63 static 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 //
74 class ReportWriterSectionData
75 {
76 public:
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
112 class Q_DECL_HIDDEN KReportDesigner::Private
113 {
114 public:
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 
221 private:
222  void loadXml(const QDomElement &data);
223 };
224 
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)
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 
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(
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
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 
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 
527 void 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
547 void KReportDesigner::setScriptSource(KReportScriptSource* source)
548 {
549  d->scriptSource = source;
550  d->updateScripts();
551 }
552 #endif
553 
554 KReportDesignerSection * 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 
605 void 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 
657 void 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 
776 void KReportDesigner::setModified(bool modified)
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 
805 void 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 */
877 void 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),
892 
893  d->rightMargin->setValue(KReportUnit::convertFromUnitToUnit(
894  d->rightMargin->value().toDouble(), oldUnit, d->currentUnit),
896 
897  d->topMargin->setValue(KReportUnit::convertFromUnitToUnit(d->topMargin->value().toDouble(),
898  oldUnit, d->currentUnit),
900 
901  d->bottomMargin->setValue(KReportUnit::convertFromUnitToUnit(
902  d->bottomMargin->value().toDouble(), oldUnit, d->currentUnit),
904 
905  d->customPageSize->setValue(
906  KReportUnit::convertFromUnitToUnit(d->customPageSize->value().toSizeF(), oldUnit,
907  d->currentUnit),
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 
922 void 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 
1000 QSize KReportDesigner::pageSizePt() const
1001 {
1002  QSize pageSizePt;
1003 
1004  if (d->set.property("page-size").value().toString() == QLatin1String("Custom")) {
1005  KReportUnit unit = pageUnit();
1006 
1007  QSizeF customSize = d->currentUnit.convertToPoint(d->set.property("custom-page-size").value().toSizeF());
1008  QPageLayout layout(QPageSize(customSize, QPageSize::Point, QString(), QPageSize::ExactMatch), d->set.property("print-orientation").value().toString()
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()
1017  pageSizePt = layout.fullRectPoints().size();
1018  }
1019 
1020  return pageSizePt;
1021 }
1022 
1023 void KReportDesigner::resizeEvent(QResizeEvent * event)
1024 {
1025  Q_UNUSED(event);
1026  d->hruler->setRulerLength(pageWidthPx());
1027 }
1028 
1029 void KReportDesigner::setDetail(KReportDesignerSectionDetail *rsd)
1030 {
1031  if (!d->detail) {
1032  int idx = 0;
1033  if (d->pageHeaderFirst) idx++;
1034  if (d->pageHeaderOdd) idx++;
1035  if (d->pageHeaderEven) idx++;
1036  if (d->pageHeaderLast) idx++;
1037  if (d->pageHeaderAny) idx++;
1038  if (d->reportHeader) idx++;
1039  d->detail = rsd;
1040  d->vboxlayout->insertWidget(idx, d->detail);
1041  }
1042 }
1043 
1045 {
1046  return d->currentUnit;
1047 }
1048 
1049 void KReportDesigner::setGridOptions(bool vis, int div)
1050 {
1051  d->showGrid->setValue(QVariant(vis));
1052  d->gridDivisions->setValue(div);
1053 }
1054 
1055 //
1056 // methods for the sectionMouse*Event()
1057 //
1059 {
1060  Q_UNUSED(s);
1061 
1062  QMenu pop;
1063 
1064  bool itemsSelected = selectionCount() > 0;
1065  if (itemsSelected) {
1066  //! @todo KF5 use KStandardAction
1067  QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-cut")), tr("Cut"), this);
1068  connect(a, SIGNAL(triggered()), this, SLOT(slotEditCut()));
1069  pop.addAction(a);
1070  //! @todo KF5 use KStandardAction
1071  a = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), tr("Copy"), this);
1072  connect(a, SIGNAL(triggered()), this, SLOT(slotEditCopy()));
1073  pop.addAction(a);
1074  }
1075  if (!d->sectionData.copy_list.isEmpty()) {
1076  QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-paste")), tr("Paste"), this);
1077  connect(a, SIGNAL(triggered()), this, SLOT(slotEditPaste()));
1078  pop.addAction(a);
1079  }
1080 
1081  if (itemsSelected) {
1082  pop.addSeparator();
1083  //! @todo KF5 use KStandard*
1084  //const KGuiItem del = KStandardGuiItem::del();
1085  //a->setToolTip(del.toolTip());
1086  //a->setShortcut(QKeySequence(QKeySequence::Delete));
1087  QAction *a = new QAction(QIcon::fromTheme(QLatin1String("edit-delete")), tr("Delete"), this);
1088  connect(a, SIGNAL(triggered()), SLOT(slotEditDelete()));
1089  pop.addAction(a);
1090  }
1091  if (!pop.actions().isEmpty()) {
1092  pop.exec(e->screenPos());
1093  }
1094 }
1095 
1096 void KReportDesigner::sectionMousePressEvent(KReportDesignerSectionView * v, QMouseEvent * e)
1097 {
1098  Q_UNUSED(v);
1099  d->pressX = e->pos().x();
1100  d->pressY = e->pos().y();
1101 }
1102 
1103 void KReportDesigner::sectionMouseReleaseEvent(KReportDesignerSectionView * v, QMouseEvent * e)
1104 {
1105  e->accept();
1106 
1107  d->releaseX = e->pos().x();
1108  d->releaseY = e->pos().y();
1109 
1110  if (e->button() == Qt::LeftButton) {
1111  QPointF pos(d->pressX, d->pressY);
1112  QPointF end(d->releaseX, d->releaseY);
1113  if (d->releaseY >= v->scene()->height()) {
1114  d->releaseY = v->scene()->height();
1115  end.setY(v->scene()->height());
1116  }
1117 
1118  if (d->releaseX >= v->scene()->width()) {
1119  d->releaseX = v->scene()->width();
1120  end.setX(v->scene()->width());
1121  }
1122 
1123  if (d->sectionData.mouseAction == ReportWriterSectionData::MouseAction::Insert) {
1124  QGraphicsItem * item = nullptr;
1125  QString classString;
1126  QString iconName;
1127  if (d->sectionData.itemToInsert == QLatin1String("org.kde.kreport.line")) {
1128  item = new KReportDesignerItemLine(v->designer(), v->scene(), pos, end);
1129  classString = tr("Line", "Report line element");
1130  iconName = QLatin1String("kreport-line-element");
1131  }
1132  else {
1133  KReportPluginManager* pluginManager = KReportPluginManager::self();
1134  KReportPluginInterface *plug = pluginManager->plugin(d->sectionData.itemToInsert);
1135  if (plug) {
1136  QObject *obj = plug->createDesignerInstance(v->designer(), v->scene(), pos);
1137  if (obj) {
1138  item = dynamic_cast<QGraphicsItem*>(obj);
1139  classString = plug->metaData()->name();
1140  iconName = plug->metaData()->iconName();
1141  }
1142  }
1143  else {
1144  kreportWarning() << "attempted to insert an unknown item";
1145  }
1146  }
1147  if (item) {
1148  item->setVisible(true);
1149  item->setSelected(true);
1150  KReportItemBase* baseReportItem = dynamic_cast<KReportItemBase*>(item);
1151  if (baseReportItem) {
1152  KPropertySet *set = baseReportItem->propertySet();
1153  KReportDesigner::addMetaProperties(set, classString, iconName);
1154  set->clearModifiedFlags();
1155  changeSet(set);
1156  if (v && v->designer()) {
1157  v->designer()->setModified(true);
1158  }
1159  emit itemInserted(d->sectionData.itemToInsert);
1160  }
1161  }
1162 
1163  d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::None;
1164  d->sectionData.itemToInsert.clear();
1165  unsetSectionCursor();
1166  }
1167  }
1168 }
1169 
1170 unsigned int KReportDesigner::selectionCount() const
1171 {
1172  if (activeScene())
1173  return activeScene()->selectedItems().count();
1174  else
1175  return 0;
1176 }
1177 
1179 {
1180  //Set the checked state of the report properties button
1181  if (set == &d->set)
1182  d->pageButton->setCheckState(Qt::Checked);
1183  else
1184  d->pageButton->setCheckState(Qt::Unchecked);
1185 
1186  if (d->itemSet != set) {
1187  d->itemSet = set;
1188  emit propertySetChanged();
1189  }
1190 }
1191 
1192 //
1193 // Actions
1194 //
1195 
1196 void KReportDesigner::slotItem(const QString &entity)
1197 {
1198  //kreportDebug() << entity;
1199  d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::Insert;
1200  d->sectionData.itemToInsert = entity;
1201  setSectionCursor(QCursor(Qt::CrossCursor));
1202 }
1203 
1205 {
1206  QGraphicsItem * item = nullptr;
1207  bool modified = false;
1208  while (selectionCount() > 0) {
1209  item = activeScene()->selectedItems().value(0);
1210  if (item) {
1211  QGraphicsScene * scene = item->scene();
1212  delete item;
1213  scene->update();
1214  d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::None;
1215  modified = true;
1216  }
1217  }
1218  activeScene()->selectedItems().clear();
1219 
1220  /*! @todo temporary: clears cut and copy lists to make sure we do not crash
1221  if weve deleted something in the list
1222  should really check if an item is in the list first
1223  and remove it. */
1224  d->sectionData.cut_list.clear();
1225  d->sectionData.copy_list.clear();
1226  if (modified) {
1227  setModified(true);
1228  }
1229 }
1230 
1231 void KReportDesigner::slotEditCut()
1232 {
1233  if (selectionCount() > 0) {
1234  //First delete any items that are curerntly in the list
1235  //so as not to leak memory
1236  qDeleteAll(d->sectionData.cut_list);
1237  d->sectionData.cut_list.clear();
1238 
1239  QGraphicsItem * item = activeScene()->selectedItems().first();
1240  bool modified = false;
1241  if (item) {
1242  d->sectionData.copy_list.clear();
1243  foreach(QGraphicsItem *item, activeScene()->selectedItems()) {
1244  d->sectionData.cut_list.append(dynamic_cast<KReportDesignerItemBase*>(item));
1245  d->sectionData.copy_list.append(dynamic_cast<KReportDesignerItemBase*>(item));
1246  }
1247  foreach(QGraphicsItem *item, activeScene()->selectedItems()) {
1248  activeScene()->removeItem(item);
1249  activeScene()->update();
1250  modified = true;
1251  }
1252  d->sectionData.selected_x_offset = 10;
1253  d->sectionData.selected_y_offset = 10;
1254  }
1255  if (modified) {
1256  setModified(true);
1257  }
1258  }
1259 }
1260 
1261 void KReportDesigner::slotEditCopy()
1262 {
1263  if (selectionCount() < 1)
1264  return;
1265 
1266  QGraphicsItem * item = activeScene()->selectedItems().first();
1267  if (item) {
1268  d->sectionData.copy_list.clear();
1269  foreach(QGraphicsItem *item, activeScene()->selectedItems()) {
1270  d->sectionData.copy_list.append(dynamic_cast<KReportDesignerItemBase*>(item));
1271  }
1272  d->sectionData.selected_x_offset = 10;
1273  d->sectionData.selected_y_offset = 10;
1274  }
1275 }
1276 
1277 void KReportDesigner::slotEditPaste()
1278 {
1279  // call the editPaste function passing it a reportsection
1280  slotEditPaste(activeScene());
1281 }
1282 
1283 void KReportDesigner::slotEditPaste(QGraphicsScene * canvas)
1284 {
1285 
1286  // paste a new item of the copy we have in the specified location
1287  if (!d->sectionData.copy_list.isEmpty()) {
1288  QList<QGraphicsItem*> activeItems = canvas->selectedItems();
1289  QGraphicsItem *activeItem = nullptr;
1290  if (activeItems.count() == 1) {
1291  activeItem = activeItems.first();
1292  }
1293  canvas->clearSelection();
1294  d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::None;
1295 
1296  //! @todo this code sucks :)
1297  //! The setPos calls only work AFTER the name has been set ?!?!?
1298 
1299  foreach(KReportDesignerItemBase *item, d->sectionData.copy_list) {
1300  KReportItemBase *obj = dynamic_cast<KReportItemBase*>(item);
1301  const QString type = obj ? obj->typeName() : QLatin1String("object");
1302  //kreportDebug() << type;
1303  KReportDesignerItemBase *ent = item->clone();
1304  KReportItemBase *new_obj = dynamic_cast<KReportItemBase*>(ent);
1305  if (new_obj) {
1306  new_obj->setEntityName(suggestEntityName(type));
1307  if (activeItem) {
1308  new_obj->setPosition(KReportItemBase::positionFromScene(QPointF(activeItem->x() + 10, activeItem->y() + 10)));
1309  } else {
1311  }
1312  new_obj->propertySet()->clearModifiedFlags();
1313  changeSet(new_obj->propertySet());
1314  }
1315  QGraphicsItem *pasted_ent = dynamic_cast<QGraphicsItem*>(ent);
1316  if (pasted_ent) {
1317  pasted_ent->setSelected(true);
1318  canvas->addItem(pasted_ent);
1319  pasted_ent->show();
1320  d->sectionData.mouseAction = ReportWriterSectionData::MouseAction::Grab;
1321  setModified(true);
1322  }
1323  }
1324  }
1325 }
1326 void KReportDesigner::slotRaiseSelected()
1327 {
1328  dynamic_cast<KReportDesignerSectionScene*>(activeScene())->raiseSelected();
1329 }
1330 
1331 void KReportDesigner::slotLowerSelected()
1332 {
1333  dynamic_cast<KReportDesignerSectionScene*>(activeScene())->lowerSelected();
1334 }
1335 
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 
1462 static bool actionPriortyLessThan(QAction* act1, QAction* act2)
1463 {
1464  if (act1->data().toInt() > 0 && act2->data().toInt() > 0) {
1465  return act1->data().toInt() < act2->data().toInt();
1466  }
1467  return false;
1468 }
1469 
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 
1517 void KReportDesigner::createActions()
1518 {
1519  d->editCutAction = new QAction(QIcon::fromTheme(QLatin1String("edit-cut")), tr("Cu&t"), this);
1520  d->editCutAction->setObjectName(QLatin1String("edit_cut"));
1521  d->editCutAction->setToolTip(tr("Cut selection to clipboard"));
1522  d->editCutAction->setShortcuts(KStandardShortcut::cut());
1523  d->editCutAction->setProperty("iconOnly", true);
1524 
1525  d->editCopyAction = new QAction(QIcon::fromTheme(QLatin1String("edit-copy")), tr("&Copy"), this);
1526  d->editCopyAction->setObjectName(QLatin1String("edit_copy"));
1527  d->editCopyAction->setToolTip(tr("Copy selection to clipboard"));
1528  d->editCopyAction->setShortcuts(KStandardShortcut::copy());
1529  d->editCopyAction->setProperty("iconOnly", true);
1530 
1531  d->editPasteAction = new QAction(QIcon::fromTheme(QLatin1String("edit-paste")), tr("&Paste"), this);
1532  d->editPasteAction->setObjectName(QLatin1String("edit_paste"));
1533  d->editPasteAction->setToolTip(tr("Paste clipboard content"));
1534  d->editPasteAction->setShortcuts(KStandardShortcut::paste());
1535  d->editPasteAction->setProperty("iconOnly", true);
1536 
1537  const KGuiItem del = KStandardGuiItem::del();
1538  d->editDeleteAction = new QAction(del.icon(), del.text(), this);
1539  d->editDeleteAction->setObjectName(QLatin1String("edit_delete"));
1540  d->editDeleteAction->setToolTip(del.toolTip());
1541  d->editDeleteAction->setWhatsThis(del.whatsThis());
1542  d->editDeleteAction->setProperty("iconOnly", true);
1543 
1544  d->sectionEdit = new QAction(tr("Edit Sections"), this);
1545  d->sectionEdit->setObjectName(QLatin1String("section_edit"));
1546 
1547  d->itemRaiseAction = new QAction(QIcon::fromTheme(QLatin1String("arrow-up")), tr("Raise"), this);
1548  d->itemRaiseAction->setObjectName(QLatin1String("item_raise"));
1549  d->itemLowerAction = new QAction(QIcon::fromTheme(QLatin1String("arrow-down")), tr("Lower"), this);
1550  d->itemLowerAction->setObjectName(QLatin1String("item_lower"));
1551 
1552  //Edit Actions
1553  connect(d->editCutAction, SIGNAL(triggered(bool)), this, SLOT(slotEditCut()));
1554  connect(d->editCopyAction, SIGNAL(triggered(bool)), this, SLOT(slotEditCopy()));
1555  connect(d->editPasteAction, SIGNAL(triggered(bool)), this, SLOT(slotEditPaste()));
1556  connect(d->editDeleteAction, SIGNAL(triggered(bool)), this, SLOT(slotEditDelete()));
1557 
1558  connect(d->sectionEdit, SIGNAL(triggered(bool)), this, SLOT(slotSectionEditor()));
1559 
1560  //Raise/Lower
1561  connect(d->itemRaiseAction, SIGNAL(triggered(bool)), this, SLOT(slotRaiseSelected()));
1562  connect(d->itemLowerAction, SIGNAL(triggered(bool)), this, SLOT(slotLowerSelected()));
1563 }
1564 
1565 void KReportDesigner::setSectionCursor(const QCursor& c)
1566 {
1567  if (d->pageFooterAny)
1568  d->pageFooterAny->setSectionCursor(c);
1569  if (d->pageFooterEven)
1570  d->pageFooterEven->setSectionCursor(c);
1571  if (d->pageFooterFirst)
1572  d->pageFooterFirst->setSectionCursor(c);
1573  if (d->pageFooterLast)
1574  d->pageFooterLast->setSectionCursor(c);
1575  if (d->pageFooterOdd)
1576  d->pageFooterOdd->setSectionCursor(c);
1577 
1578  if (d->pageHeaderAny)
1579  d->pageHeaderAny->setSectionCursor(c);
1580  if (d->pageHeaderEven)
1581  d->pageHeaderEven->setSectionCursor(c);
1582  if (d->pageHeaderFirst)
1583  d->pageHeaderFirst->setSectionCursor(c);
1584  if (d->pageHeaderLast)
1585  d->pageHeaderLast->setSectionCursor(c);
1586  if (d->pageHeaderOdd)
1587  d->pageHeaderOdd->setSectionCursor(c);
1588 
1589  if (d->detail)
1590  d->detail->setSectionCursor(c);
1591 }
1592 
1593 void KReportDesigner::unsetSectionCursor()
1594 {
1595  if (d->pageFooterAny)
1596  d->pageFooterAny->unsetSectionCursor();
1597  if (d->pageFooterEven)
1598  d->pageFooterEven->unsetSectionCursor();
1599  if (d->pageFooterFirst)
1600  d->pageFooterFirst->unsetSectionCursor();
1601  if (d->pageFooterLast)
1602  d->pageFooterLast->unsetSectionCursor();
1603  if (d->pageFooterOdd)
1604  d->pageFooterOdd->unsetSectionCursor();
1605 
1606  if (d->pageHeaderAny)
1607  d->pageHeaderAny->unsetSectionCursor();
1608  if (d->pageHeaderEven)
1609  d->pageHeaderEven->unsetSectionCursor();
1610  if (d->pageHeaderFirst)
1611  d->pageHeaderFirst->unsetSectionCursor();
1612  if (d->pageHeaderLast)
1613  d->pageHeaderLast->unsetSectionCursor();
1614  if (d->pageHeaderOdd)
1615  d->pageHeaderOdd->unsetSectionCursor();
1616 
1617  if (d->detail)
1618  d->detail->unsetSectionCursor();
1619 }
1620 
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 
1657 void KReportDesigner::plugItemActions(const QList<QAction*> &actList)
1658 {
1659  foreach(QAction *a, actList) {
1660  connect(a, SIGNAL(triggered(bool)), this, SLOT(slotItemTriggered(bool)));
1661  }
1662 }
1663 
1664 void KReportDesigner::slotItemTriggered(bool checked)
1665 {
1666  if (!checked) {
1667  return;
1668  }
1669  QObject *theSender = sender();
1670  if (!theSender) {
1671  return;
1672  }
1673  slotItem(theSender->objectName());
1674 }
1675 
1677  const QString &iconName)
1678 {
1679  Q_ASSERT(set);
1680  KProperty *prop;
1681  set->addProperty(prop = new KProperty("this:classString", classString));
1682  prop->setVisible(false);
1683  set->addProperty(prop = new KProperty("this:iconName", iconName));
1684  prop->setVisible(false);
1685 }
1686 
1687 void KReportDesigner::recalculateMaxMargins()
1688 {
1689  QSize pageSize = pageSizePt();
1690  d->leftMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.width() - d->currentUnit.convertToPoint(d->rightMargin->value().toReal()) - SMALLEST_PAGE_SIZE_PT));
1691  d->rightMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.width() - d->currentUnit.convertToPoint(d->leftMargin->value().toReal())- SMALLEST_PAGE_SIZE_PT));
1692  d->topMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.height() - d->currentUnit.convertToPoint(d->bottomMargin->value().toReal())- SMALLEST_PAGE_SIZE_PT));
1693  d->bottomMargin->setOption("max", d->currentUnit.convertFromPoint(pageSize.height() - d->currentUnit.convertToPoint(d->topMargin->value().toReal())- SMALLEST_PAGE_SIZE_PT));
1694 }
QByteArray name() const
QIcon icon() const
void adjustSize()
T & first()
Base class for items that are drawn syncronously.
QPoint pos() const const
void propertyChanged(KPropertySet &set, KProperty &property)
bool isModified() const
Return true if the design has been modified.
QString whatsThis() const
This class is the base to all Report Section's visual representation.
void setGridOptions(bool visible, int divisions)
Sets the parameters for the display of the background gridpoints.
QString toString(int indent) const const
int count() const const
static KReportSectionData::Type sectionTypeFromString(const QString &s)
KReportDesignerSection * createSection()
Creates new section.
The central detail section which contains the bulk of the report.
bool isValid() const
Returns true if type of this unit is valid.
Converts between different units.
Definition: KReportUnit.h:70
KReportDesignerSectionDetail * detailSection() const
Return a pointer to the detail section.
QGraphicsItemList items() const
Return the items in the section Only return top-level items ...
QDomNode firstChild() const const
QDomElement toElement() const const
QByteArray toLower() const const
QList< QAction * > actions() const const
QString number(int n, int base)
void addItem(QGraphicsItem *item)
qreal getSelectionPressX() const
KReportDesigner(QWidget *parent=nullptr)
Constructor that create a blank designer.
Qt::MouseButton button() const const
QString tagName() const const
void setModified(bool modified)
Sets the modified status, defaulting to true for modified.
void insertSection(KReportSectionData::Type type)
Create a new section and insert it into the report.
QCA_EXPORT void init()
int count(const T &value) const const
QLayout * layout() const const
QString text() const
static QString sectionTypeString(KReportSectionData::Type type)
static KReportUnit::Type symbolToType(const QString &symbol)
Returns a unit symbol string to type.
void update()
static void addMetaProperties(KPropertySet *set, const QString &classString, const QString &iconName)
Adds meta-properties to the property set set for consumption by property editor.
qreal countSelectionWidth() const
virtual bool event(QEvent *event) override
QDomText createTextNode(const QString &value)
QIcon fromTheme(const QString &name)
KREPORT_EXPORT QString pageSizeKey(QPageSize::PageSizeId id)
QAction * addSeparator()
QSize sizeHint() const override
Give a hint on the size of the widget.
QObject * sender() const const
QPoint screenPos() const const
virtual QString typeName() const =0
Return the item type as a string.
QList::const_iterator constBegin() const const
int x() const const
int y() const const
int width() const const
QMessageBox::StandardButton warning(QWidget *parent, const QString &title, const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton)
QDomElement createElement(const QString &tagName)
LeftButton
void removeSection(KReportSectionData::Type type)
Deletes the section specified.
QList< QAction * > designerActions()
Populates the toolbar with actions that can be applied to the report Actions are created as children ...
Manager class for finding and loading available plugins.
KPropertySet * propertySet() const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QString nodeValue() const const
QString iconName() const
void sectionContextMenuEvent(KReportDesignerSectionScene *scene, QGraphicsSceneContextMenuEvent *event)
Handle the context menu event for a report section.
QStringList types(Mode mode=Writing)
KReportUnit pageUnit() const
Return the current unit assigned to the report.
QAction * addAction(const QString &text)
void setAttribute(const QString &name, const QString &value)
QList< QGraphicsItem * > selectedItems() const const
void clear()
void prepend(const T &value)
QPointF getReleasePoint() const
QDomNode item(int index) const const
bool isEntityNameUnique(const QString &name, KReportItemBase *ignore=nullptr) const
Checks if the supplied name is unique among all entities.
KREPORT_EXPORT QStringList pageFormatNames()
qreal getSelectionPressY() const
static QStringList descriptions(const QList< Type > &types)
Returns the list of (translated) description strings for given list of types.
const KReportPluginMetaData * metaData() const
KReportDataSource * reportDataSource() const
Return a pointer to the reports data.
const QList< QKeySequence > & cut()
KREPORT_EXPORT QStringList pageFormatKeys()
QGraphicsScene * scene() const const
bool removeOne(const T &value)
QString name() const
void setPosition(const QPointF &ptPos)
Sets position for the element.
Horizontal
bool isEmpty() const const
CrossCursor
KREPORT_EXPORT QPageSize::PageSizeId defaultSize()
void setSelected(bool selected)
Abstraction of report data source.
KReportDesignerSection * section(KReportSectionData::Type type) const
Return a pointer to the section specified.
int toInt(bool *ok) const const
bool startsWith(const QByteArray &ba) const const
static qreal parseValue(const QString &value, qreal defaultVal=0.0)
Parses common KReport and ODF values, like "10cm", "5mm" to pt.
void sectionMouseReleaseEvent(KReportDesignerSectionView *v, QMouseEvent *e)
Handle the mouse release event for a report section.
bool isEmpty() const const
void setVisible(bool visible)
void setActiveScene(QGraphicsScene *scene)
Sets the active Scene.
QDomNodeList childNodes() const const
QString reportTitle() const
Return the title of the report.
void changeSet(KPropertySet *set)
Sets the property set for the currently selected item.
QString suggestEntityName(const QString &name) const
Return a unique name that can be used by the entity.
QDomElement document() const
Return an XML description of the report.
KPropertySet * selectedItemPropertySet() const
Return the property set for the curently selected item.
void setCheckable(bool)
QGraphicsScene * activeScene() const
qreal countSelectionHeight() const
QString nodeName() const const
void insert(int i, const T &value)
void show()
QVariant data() const const
void setData(const QVariant &userData)
QPointF getPressPoint() const
static QPointF positionFromScene(const QPointF &pos)
Helper function mapping from screen units to points, pos is in pixels.
KGuiItem del()
QString toLower() const const
void update(qreal x, qreal y, qreal w, qreal h)
QString toolTip() const
QList::const_iterator constEnd() const const
QStringList fieldKeys() const
void setVisible(bool visible)
void addProperty(KProperty *property, const QByteArray &group="common")
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QDomNode appendChild(const QDomNode &newChild)
Abstraction of report script source.
static QStringList symbols(const QList< Type > &types)
Returns the list of unit symbols for the given types.
void setObjectName(const QString &name)
void setDataSource(KReportDataSource *source)
Sets the report data The report data interface contains functions to retrieve data and information ab...
const QList< QKeySequence > & paste()
QVariant value() const
void setReportTitle(const QString &title)
Sets the title of the reportData.
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
QList::iterator begin()
void clearModifiedFlags()
static QList< QAction * > itemActions(QActionGroup *group=nullptr)
Returns a list of actions that represent the entities that can be inserted into the report.
The ReportDesigner is the main widget for designing a report.
QString attribute(const QString &name, const QString &defValue) const const
QAction * addAction(QAction *action)
~KReportDesigner() override
Desctructor.
bool isElement() const const
QList::iterator end()
void setSeparator(bool b)
QString tr(const char *sourceText, const char *disambiguation, int n)
qreal x() const const
qreal y() const const
static QList< Type > allTypes()
Returns list of all supported types (without Invalid)
const QList< QKeySequence > & copy()
QAction * exec()
void removeItem(QGraphicsItem *item)
void clearSelection()
int pageWidthPx() const
Calculate the width of the page in pixels given the paper size, orientation, dpi and margin.
void accept()
QString toString() const const
An interface for plugins delivering KReport elements.
QStringList fieldNames() const
KREPORT_EXPORT QPageSize::PageSizeId pageSize(const QString &key)
Base class for report items used within the designer GUI.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Nov 28 2023 04:10:24 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.