File indexing completed on 2024-04-28 04:42:10
0001 /* This file is part of the KDE project 0002 * Copyright (C) 2001-2007 by OpenMFG, LLC (info@openmfg.com) 0003 * Copyright (C) 2007-2008 by Adam Pigg (adam@piggz.co.uk) 0004 * Copyright (C) 2014 Jarosław Staniek <staniek@kde.org> 0005 * 0006 * This library is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU Lesser General Public 0008 * License as published by the Free Software Foundation; either 0009 * version 2.1 of the License, or (at your option) any later version. 0010 * 0011 * This library is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0014 * Lesser General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU Lesser General Public 0017 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include "KReportDesignerSection.h" 0021 0022 #include "KReportDesignerSectionScene.h" 0023 #include "KReportDesignerSectionView.h" 0024 #include "KReportDesigner.h" 0025 #include "KReportDesignerItemBase.h" 0026 #include "KReportUtils.h" 0027 #include "KReportPluginInterface.h" 0028 #include "KReportPluginManager.h" 0029 #include "KReportDesignerItemRectBase.h" 0030 #include "KReportDesignerItemLine.h" 0031 #include "KReportRuler_p.h" 0032 #include "KReportZoomHandler_p.h" 0033 #include "KReportUtils_p.h" 0034 #include "KReportPluginMetaData.h" 0035 #include "kreport_debug.h" 0036 0037 #include <QLabel> 0038 #include <QFrame> 0039 #include <QDomDocument> 0040 #include <QLayout> 0041 #include <QGridLayout> 0042 #include <QMouseEvent> 0043 #include <QApplication> 0044 #include <QApplication> 0045 #include <QIcon> 0046 0047 0048 //! @internal 0049 class ReportResizeBar : public QFrame 0050 { 0051 Q_OBJECT 0052 public: 0053 explicit ReportResizeBar(QWidget * parent = nullptr, Qt::WindowFlags f = nullptr); 0054 0055 Q_SIGNALS: 0056 void barDragged(int delta); 0057 0058 protected: 0059 void mouseMoveEvent(QMouseEvent * e) override; 0060 }; 0061 0062 //! @internal 0063 class KReportDesignerSectionTitle : public QLabel 0064 { 0065 Q_OBJECT 0066 public: 0067 explicit KReportDesignerSectionTitle(QWidget *parent = nullptr); 0068 ~KReportDesignerSectionTitle() override; 0069 0070 Q_SIGNALS: 0071 void clicked(); 0072 0073 protected: 0074 void paintEvent(QPaintEvent* event) override; 0075 void mousePressEvent(QMouseEvent *event) override; 0076 }; 0077 0078 //! @internal 0079 class Q_DECL_HIDDEN KReportDesignerSection::Private 0080 { 0081 public: 0082 explicit Private() 0083 {} 0084 0085 ~Private() 0086 {} 0087 0088 KReportDesignerSectionTitle *title; 0089 KReportDesignerSectionScene *scene; 0090 ReportResizeBar *resizeBar; 0091 KReportDesignerSectionView *sceneView; 0092 KReportDesigner*reportDesigner; 0093 KReportRuler *sectionRuler; 0094 0095 KReportSectionData *sectionData; 0096 int dpiY; 0097 bool slotPropertyChangedEnabled = true; 0098 }; 0099 0100 0101 KReportDesignerSection::KReportDesignerSection(KReportDesigner * rptdes, 0102 const KReportZoomHandler &zoomHandler) 0103 : QWidget(rptdes) 0104 , d(new Private()) 0105 { 0106 Q_ASSERT(rptdes); 0107 d->sectionData = new KReportSectionData(this); 0108 connect(d->sectionData->propertySet(), SIGNAL(propertyChanged(KPropertySet&,KProperty&)), 0109 this, SLOT(slotPropertyChanged(KPropertySet&,KProperty&))); 0110 0111 d->dpiY = KReportPrivate::dpiY(); 0112 0113 d->reportDesigner = rptdes; 0114 setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0115 0116 QGridLayout * glayout = new QGridLayout(this); 0117 glayout->setSpacing(0); 0118 glayout->setMargin(0); 0119 glayout->setColumnStretch(1, 1); 0120 glayout->setRowStretch(1, 1); 0121 glayout->setSizeConstraint(QLayout::SetFixedSize); 0122 0123 // ok create the base interface 0124 d->title = new KReportDesignerSectionTitle(this); 0125 d->title->setObjectName(QLatin1String("detail")); 0126 d->title->setText(tr("Detail")); 0127 0128 d->sectionRuler = new KReportRuler(this, Qt::Vertical, zoomHandler); 0129 d->sectionRuler->setUnit(d->reportDesigner->pageUnit()); 0130 d->scene = new KReportDesignerSectionScene(d->reportDesigner->pageWidthPx(), d->dpiY, rptdes); 0131 d->scene->setBackgroundBrush(d->sectionData->backgroundColor()); 0132 0133 d->sceneView = new KReportDesignerSectionView(rptdes, d->scene, this); 0134 d->sceneView->setObjectName(QLatin1String("scene view")); 0135 d->sceneView->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); 0136 0137 d->resizeBar = new ReportResizeBar(this); 0138 0139 connect(d->resizeBar, SIGNAL(barDragged(int)), this, SLOT(slotResizeBarDragged(int))); 0140 connect(d->reportDesigner, &KReportDesigner::pagePropertyChanged, 0141 this, &KReportDesignerSection::slotPageOptionsChanged); 0142 connect(d->scene, &KReportDesignerSectionScene::clicked, this, &KReportDesignerSection::slotSceneClicked); 0143 connect(d->scene, SIGNAL(lostFocus()), d->title, SLOT(update())); 0144 connect(d->title, &KReportDesignerSectionTitle::clicked, this, &KReportDesignerSection::slotSceneClicked); 0145 0146 glayout->addWidget(d->title, 0, 0, 1, 2); 0147 glayout->addWidget(d->sectionRuler, 1, 0); 0148 glayout->addWidget(d->sceneView , 1, 1); 0149 glayout->addWidget(d->resizeBar, 2, 0, 1, 2); 0150 d->sectionRuler->setFixedWidth(d->sectionRuler->sizeHint().width()); 0151 0152 setLayout(glayout); 0153 slotResizeBarDragged(0); 0154 } 0155 0156 KReportDesignerSection::~KReportDesignerSection() 0157 { 0158 delete d; 0159 } 0160 0161 void KReportDesignerSection::setTitle(const QString & s) 0162 { 0163 d->title->setText(s); 0164 } 0165 0166 void KReportDesignerSection::slotResizeBarDragged(int delta, bool changeSet) 0167 { 0168 if (d->sceneView->designer() && d->sceneView->designer()->propertySet()->property("page-size").value().toString() == QLatin1String("Labels")) { 0169 return; // we don't want to allow this on reports that are for labels 0170 } 0171 0172 if (changeSet) { 0173 slotSceneClicked(); // switches property set to this section 0174 } 0175 0176 qreal h = d->scene->height() + delta; 0177 0178 if (h < 1) h = 1; 0179 0180 h = d->scene->gridPoint(QPointF(0, h)).y(); 0181 d->slotPropertyChangedEnabled = false; // reduce updates 0182 d->sectionData->setHeight(INCH_TO_POINT(h / d->dpiY), 0183 delta == 0 ? KProperty::ValueOption::IgnoreOld 0184 : KProperty::ValueOption::None); 0185 d->slotPropertyChangedEnabled = true; 0186 d->sectionRuler->setRulerLength(h); 0187 0188 const QRect newSceneRect(0, 0, d->scene->width(), h); 0189 if (d->scene->sceneRect() != newSceneRect) { 0190 d->scene->setSceneRect(newSceneRect); 0191 } 0192 d->sceneView->resizeContents(newSceneRect.size()); 0193 0194 if (delta != 0) { 0195 d->reportDesigner->setModified(true); 0196 } 0197 } 0198 0199 void KReportDesignerSection::buildXML(QDomDocument *doc, QDomElement *section) 0200 { 0201 KReportUtils::setAttribute(section, QLatin1String("svg:height"), d->sectionData->height()); 0202 section->setAttribute(QLatin1String("fo:background-color"), d->sectionData->backgroundColor().name()); 0203 0204 // now get a list of all the QGraphicsItems on this scene and output them. 0205 QGraphicsItemList list = d->scene->items(); 0206 for (QGraphicsItemList::iterator it = list.begin(); 0207 it != list.end(); ++it) { 0208 KReportDesignerItemBase::buildXML((*it), doc, section); 0209 } 0210 } 0211 0212 void KReportDesignerSection::initFromXML(const QDomNode & section) 0213 { 0214 QDomNodeList nl = section.childNodes(); 0215 QDomNode node; 0216 QString n; 0217 0218 qreal ptHeight = KReportUtils::readSizeAttributes(section.toElement(), QSizeF(DEFAULT_SECTION_SIZE_PT, DEFAULT_SECTION_SIZE_PT)).height(); 0219 d->sectionData->setHeight(ptHeight); 0220 0221 qreal h = POINT_TO_INCH(ptHeight) * d->dpiY; 0222 //kreportDebug() << "Section Height: " << h; 0223 d->scene->setSceneRect(0, 0, d->scene->width(), h); 0224 slotResizeBarDragged(0); 0225 d->sectionData->setBackgroundColor(KReportUtils::attr( 0226 section.toElement(), QLatin1String("fo:background-color"), QColor(Qt::white))); 0227 d->sectionData->propertySet()->clearModifiedFlags(); 0228 0229 KReportPluginManager* manager = KReportPluginManager::self(); 0230 for (int i = 0; i < nl.count(); ++i) { 0231 node = nl.item(i); 0232 n = node.nodeName(); 0233 QObject *obj = nullptr; 0234 if (n.startsWith(QLatin1String("report:"))) { 0235 //Load objects 0236 //report:line is a special case as it is not a plugin 0237 KReportPluginInterface *plugin = nullptr; 0238 QString reportItemName = n.mid(qstrlen("report:")); 0239 if (reportItemName == QLatin1String("line")) { 0240 obj = new KReportDesignerItemLine(node, d->sceneView->designer(), d->scene); 0241 } else { 0242 plugin = manager->plugin(reportItemName); 0243 if (plugin) { 0244 obj = plugin->createDesignerInstance(node, d->reportDesigner, d->scene); 0245 } 0246 } 0247 if (obj) { 0248 KReportDesignerItemRectBase *entity = dynamic_cast<KReportDesignerItemRectBase*>(obj); 0249 if (entity) { 0250 entity->setVisible(true); 0251 } 0252 KReportItemBase *item = dynamic_cast<KReportItemBase*>(obj); 0253 if (item) { 0254 item->setUnit(d->reportDesigner->pageUnit()); 0255 if (plugin) { 0256 KReportDesigner::addMetaProperties(item->propertySet(), 0257 plugin->metaData()->name(), 0258 plugin->metaData()->iconName()); 0259 } 0260 item->propertySet()->clearModifiedFlags(); 0261 } 0262 } 0263 } 0264 if (!obj) { 0265 kreportWarning() << "Unknown element" << n << "while parsing section" 0266 << section.toElement().tagName(); 0267 } 0268 } 0269 } 0270 0271 QSize KReportDesignerSection::sizeHint() const 0272 { 0273 return QSize(d->scene->width() + d->sectionRuler->frameSize().width(), d->title->frameSize().height() + d->sceneView->sizeHint().height() + d->resizeBar->frameSize().height()); 0274 } 0275 0276 void KReportDesignerSection::slotPageOptionsChanged(KPropertySet &set) 0277 { 0278 Q_UNUSED(set) 0279 0280 KReportUnit unit = d->reportDesigner->pageUnit(); 0281 d->sectionData->setUnit(unit); 0282 0283 //update items position with unit 0284 QList<QGraphicsItem*> itms = d->scene->items(); 0285 for (int i = 0; i < itms.size(); ++i) { 0286 KReportItemBase *obj = dynamic_cast<KReportItemBase*>(itms[i]); 0287 if (obj) { 0288 obj->setUnit(unit); 0289 } 0290 } 0291 0292 d->scene->setSceneRect(0, 0, d->reportDesigner->pageWidthPx(), d->scene->height()); 0293 d->title->setMinimumWidth(d->reportDesigner->pageWidthPx() + d->sectionRuler->frameSize().width()); 0294 d->sectionRuler->setUnit(d->reportDesigner->pageUnit()); 0295 0296 //Trigger a redraw of the background 0297 d->sceneView->resizeContents(QSize(d->scene->width(), d->scene->height())); 0298 0299 d->sceneView->resetCachedContent(); 0300 d->sceneView->update(); 0301 0302 d->reportDesigner->adjustSize(); 0303 d->reportDesigner->repaint(); 0304 } 0305 0306 void KReportDesignerSection::slotSceneClicked() 0307 { 0308 d->reportDesigner->setActiveScene(d->scene); 0309 d->reportDesigner->changeSet(d->sectionData->propertySet()); 0310 } 0311 0312 void KReportDesignerSection::slotPropertyChanged(KPropertySet &s, KProperty &p) 0313 { 0314 Q_UNUSED(s) 0315 if (!d->slotPropertyChangedEnabled) { 0316 return; 0317 } 0318 //kreportDebug() << p.name(); 0319 0320 //Handle Background Color 0321 if (p.name() == "background-color") { 0322 d->scene->setBackgroundBrush(p.value().value<QColor>()); 0323 } 0324 0325 if (p.name() == "height") { 0326 const QRect newSceneRect(0, 0, d->scene->width(), POINT_TO_INCH(d->sectionData->height()) * d->dpiY); 0327 if (d->scene->sceneRect() != newSceneRect) { 0328 d->scene->setSceneRect(newSceneRect); 0329 } 0330 d->sceneView->resizeContents(newSceneRect.size()); 0331 } 0332 0333 if (d->reportDesigner) 0334 d->reportDesigner->setModified(true); 0335 0336 d->sceneView->resetCachedContent(); 0337 d->scene->update(); 0338 } 0339 0340 void KReportDesignerSection::setSectionCursor(const QCursor& c) 0341 { 0342 if (d->sceneView) 0343 d->sceneView->setCursor(c); 0344 } 0345 0346 void KReportDesignerSection::unsetSectionCursor() 0347 { 0348 if (d->sceneView) 0349 d->sceneView->unsetCursor(); 0350 } 0351 0352 QGraphicsItemList KReportDesignerSection::items() const 0353 { 0354 QGraphicsItemList items; 0355 0356 if (d->scene) { 0357 foreach (QGraphicsItem *itm, d->scene->items()) { 0358 if (itm->parentItem() == nullptr) { 0359 items << itm; 0360 } 0361 } 0362 } 0363 0364 return items; 0365 } 0366 0367 0368 // 0369 // class ReportResizeBar 0370 // 0371 ReportResizeBar::ReportResizeBar(QWidget * parent, Qt::WindowFlags f) 0372 : QFrame(parent, f) 0373 { 0374 setCursor(QCursor(Qt::SizeVerCursor)); 0375 setFrameStyle(QFrame::HLine); 0376 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); 0377 } 0378 0379 void ReportResizeBar::mouseMoveEvent(QMouseEvent * e) 0380 { 0381 e->accept(); 0382 emit barDragged(e->y()); 0383 } 0384 0385 //============================================================================= 0386 0387 KReportDesignerSectionTitle::KReportDesignerSectionTitle(QWidget*parent) : QLabel(parent) 0388 { 0389 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); 0390 setAlignment(Qt::AlignLeft | Qt::AlignTop); 0391 setMinimumHeight(qMax(fontMetrics().lineSpacing(),16 + 2)); //16 = Small icon size 0392 } 0393 0394 KReportDesignerSectionTitle::~KReportDesignerSectionTitle() 0395 { 0396 } 0397 0398 //! \return true if \a o has parent \a par. 0399 static bool hasParent(QObject* par, QObject* o) 0400 { 0401 if (!o || !par) 0402 return false; 0403 while (o && o != par) 0404 o = o->parent(); 0405 return o == par; 0406 } 0407 0408 static void replaceColors(QPixmap* original, const QColor& color) 0409 { 0410 QImage dest(original->toImage()); 0411 QPainter p(&dest); 0412 p.setCompositionMode(QPainter::CompositionMode_SourceIn); 0413 p.fillRect(dest.rect(), color); 0414 *original = QPixmap::fromImage(dest); 0415 } 0416 0417 void KReportDesignerSectionTitle::paintEvent(QPaintEvent * event) 0418 { 0419 QPainter painter(this); 0420 KReportDesignerSection* section = dynamic_cast<KReportDesignerSection*>(parent()); 0421 if (section) { 0422 const bool current = section->d->scene == section->d->reportDesigner->activeScene(); 0423 QPalette::ColorGroup cg = QPalette::Inactive; 0424 QWidget *activeWindow = QApplication::activeWindow(); 0425 if (activeWindow) { 0426 QWidget *par = activeWindow->focusWidget(); 0427 if (qobject_cast<KReportDesignerSectionView*>(par)) { 0428 par = par->parentWidget(); // we're close, pick common parent 0429 } 0430 if (hasParent(par, this)) { 0431 cg = QPalette::Active; 0432 } 0433 } 0434 if (current) { 0435 painter.fillRect(rect(), palette().brush(cg, QPalette::Highlight)); 0436 } 0437 painter.setPen(palette().color(cg, current ? QPalette::HighlightedText : QPalette::WindowText)); 0438 QPixmap pixmap(QIcon::fromTheme(QLatin1String("arrow-down")).pixmap(16,16)); 0439 replaceColors(&pixmap, painter.pen().color()); 0440 const int left = 25; 0441 painter.drawPixmap(QPoint(left, (height() - pixmap.height()) / 2), pixmap); 0442 0443 painter.drawText(rect().adjusted(left + pixmap.width() + 4, 0, 0, 0), Qt::AlignLeft | Qt::AlignVCenter, text()); 0444 } 0445 QFrame::paintEvent(event); 0446 } 0447 0448 void KReportDesignerSectionTitle::mousePressEvent(QMouseEvent *event) 0449 { 0450 QLabel::mousePressEvent(event); 0451 if (event->button() == Qt::LeftButton) { 0452 emit clicked(); 0453 } 0454 } 0455 0456 #include "KReportDesignerSection.moc"