/*************************************************************************** * This file is part of the Lime Report project * * Copyright (C) 2015 by Alexander Arin * * arin_a@bk.ru * * * ** GNU General Public License Usage ** * * * This library is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ** GNU Lesser General Public License ** * * * This library is free software: you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of the * * License, or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public * * License along with this library. * * If not, see . * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * ****************************************************************************/ #include "lrhorizontallayout.h" #include "lrdesignelementsfactory.h" #include #include #include #include #include "lrbasedesignintf.h" const QString xmlTag = "HLayout"; namespace { LimeReport::BaseDesignIntf *createHLayout(QObject *owner, LimeReport::BaseDesignIntf *parent) { return new LimeReport::HorizontalLayout(owner, parent); } bool registred = LimeReport::DesignElementsFactory::instance().registerCreator( xmlTag, LimeReport::ItemAttribs(QObject::tr("HLayout"), LimeReport::Const::bandTAG), createHLayout ); } namespace LimeReport { bool lessThen(BaseDesignIntf *c1, BaseDesignIntf* c2){ return c1->pos().x()pos().x(); } HorizontalLayout::HorizontalLayout(QObject *owner, QGraphicsItem *parent) : LayoutDesignIntf(xmlTag, owner, parent),m_isRelocating(false),m_layoutType(Layout) { setPossibleResizeDirectionFlags(ResizeBottom); m_layoutMarker = new LayoutMarker(this); m_layoutMarker->setParentItem(this); m_layoutMarker->setColor(Qt::red); m_layoutMarker->setHeight(height()); m_layoutMarker->setZValue(1); } HorizontalLayout::~HorizontalLayout() { if (m_layoutMarker) { delete m_layoutMarker; m_layoutMarker=0; } } BaseDesignIntf *HorizontalLayout::createSameTypeItem(QObject *owner, QGraphicsItem *parent) { return new LimeReport::HorizontalLayout(owner, parent); } void HorizontalLayout::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event) // if ((itemMode() & LayoutEditMode) || isSelected()){ // setChildVisibility(false); // } } void HorizontalLayout::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { Q_UNUSED(event) // setChildVisibility(true); } void HorizontalLayout::geometryChangedEvent(QRectF newRect, QRectF ) { m_layoutMarker->setHeight(newRect.height()); relocateChildren(); if (m_layoutType == Table && !m_isRelocating){ divideSpace(); } } void HorizontalLayout::setChildVisibility(bool value){ foreach(QGraphicsItem* child,childItems()){ BaseDesignIntf* item = dynamic_cast(child); if(item) item->setVisible(value); } } int HorizontalLayout::childrenCount() { return m_children.size(); } void HorizontalLayout::initMode(BaseDesignIntf::ItemMode mode) { BaseDesignIntf::initMode(mode); if ((mode==PreviewMode)||(mode==PrintMode)){ m_layoutMarker->setVisible(false); } else { m_layoutMarker->setVisible(true); } } bool HorizontalLayout::canBeSplitted(int height) const { foreach(QGraphicsItem* qgItem,childItems()){ BaseDesignIntf* item=dynamic_cast(qgItem); if (item) if (!item->canBeSplitted(height-item->pos().y())) return false; } return true; } BaseDesignIntf *HorizontalLayout::cloneUpperPart(int height, QObject *owner, QGraphicsItem *parent) { HorizontalLayout* upperPart = dynamic_cast(createSameTypeItem(owner,parent)); upperPart->initFromItem(this); qreal maxHeight = 0; foreach(BaseDesignIntf* item,childBaseItems()){ if ((item->geometry().top()geometry().bottom()>height)){ int sliceHeight = height-item->geometry().top(); if (item->canBeSplitted(sliceHeight)){ BaseDesignIntf* slicedPart = item->cloneUpperPart(sliceHeight,upperPart,upperPart); if (maxHeightheight()) maxHeight = slicedPart->height(); } else { item->cloneEmpty(sliceHeight,upperPart,upperPart); item->setPos(item->pos().x(),item->pos().y()+((height+1)-item->geometry().top())); } } } foreach(BaseDesignIntf* item, upperPart->childBaseItems()){ item->setHeight((maxHeightsetHeight(height); return upperPart; } BaseDesignIntf *HorizontalLayout::cloneBottomPart(int height, QObject *owner, QGraphicsItem *parent) { qreal maxHeight = 0; HorizontalLayout* bottomPart = dynamic_cast(createSameTypeItem(owner,parent)); bottomPart->initFromItem(this); foreach(BaseDesignIntf* item,childBaseItems()){ if ((item->geometry().top()geometry().bottom()>height)){ BaseDesignIntf* tmpItem=item->cloneBottomPart(height,bottomPart,bottomPart); tmpItem->setPos(tmpItem->pos().x(),0); if (maxHeightheight()) maxHeight = tmpItem->height(); } } if (!bottomPart->isEmpty()){ foreach (BaseDesignIntf* item, bottomPart->childBaseItems()) { item->setHeight(maxHeight); } bottomPart->setHeight(maxHeight); } return bottomPart; } void HorizontalLayout::setItemAlign(const BaseDesignIntf::ItemAlign &itemAlign) { if (itemAlign == ParentWidthItemAlign) setLayoutType(Table); BaseDesignIntf::setItemAlign(itemAlign); } void HorizontalLayout::setBorderLinesFlags(BaseDesignIntf::BorderLines flags) { BaseDesignIntf::setBorderLinesFlags(flags); if (flags!=0) relocateChildren(); } void HorizontalLayout::restoreChild(BaseDesignIntf* item){ if (m_children.contains(item)) return; m_isRelocating=true; foreach (BaseDesignIntf* child, childBaseItems()) { if (child->pos()==item->pos()){ int index = m_children.indexOf(child)-1; m_children.insert(index,item); child->setPos(item->pos().x()+item->width(),0); break; } } connect(item,SIGNAL(destroyed(QObject*)),this,SLOT(slotOnChildDestroy(QObject*))); connect(item,SIGNAL(geometryChanged(QObject*,QRectF,QRectF)), this,SLOT(slotOnChildGeometryChanged(QObject*,QRectF,QRectF))); connect(item, SIGNAL(itemAlignChanged(BaseDesignIntf*,ItemAlign,ItemAlign)), this, SLOT(slotOnChildItemAlignChanged(BaseDesignIntf*,ItemAlign,ItemAlign))); item->setFixedPos(true); item->setPossibleResizeDirectionFlags(ResizeRight | ResizeBottom); item->setParent(this); item->setParentItem(this); updateLayoutSize(); m_isRelocating=false; } bool HorizontalLayout::isEmpty() const { bool isEmpty = true; bool allItemsIsText = true; foreach (QGraphicsItem* qgItem, childItems()) { ContentItemDesignIntf* item = dynamic_cast(qgItem); if (item && !item->content().isEmpty()) isEmpty = false; if (!item && dynamic_cast(qgItem)) allItemsIsText = false; } return (isEmpty && allItemsIsText); } void HorizontalLayout::addChild(BaseDesignIntf *item, bool updateSize) { if (m_children.count() > 0) item->setPos(m_children.last()->pos().x() + m_children.last()->width(), 0); else item->setPos(0, 0); m_children.append(item); item->setParentItem(this); item->setParent(this); item->setFixedPos(true); item->setPossibleResizeDirectionFlags(ResizeRight | ResizeBottom); connect(item,SIGNAL(destroyed(QObject*)),this,SLOT(slotOnChildDestroy(QObject*))); connect(item,SIGNAL(geometryChanged(QObject*,QRectF,QRectF)),this,SLOT(slotOnChildGeometryChanged(QObject*,QRectF,QRectF))); connect(item, SIGNAL(itemVisibleHasChanged(BaseDesignIntf*)),this,SLOT(slotOnChildVisibleHasChanged(BaseDesignIntf*))); if (updateSize){ relocateChildren(); updateLayoutSize(); } } void HorizontalLayout::collectionLoadFinished(const QString &collectionName) { ItemDesignIntf::collectionLoadFinished(collectionName); if (collectionName.compare("children",Qt::CaseInsensitive)==0){ #ifdef HAVE_QT5 foreach(QObject* obj,children()){ #else foreach(QObject* obj,QObject::children()){ #endif BaseDesignIntf* item = dynamic_cast(obj); if (item) { addChild(item,false); } } } } void HorizontalLayout::objectLoadFinished() { m_layoutMarker->setHeight(height()); LayoutDesignIntf::objectLoadFinished(); } void HorizontalLayout::updateLayoutSize() { int w = ((borderLines() != 0) ? borderLineSize() : 0)*2; qreal h = 0; foreach(BaseDesignIntf* item, m_children){ if (item->isVisible()){ if (hheight()) h=item->height(); w+=item->width(); } } if (h>0) setHeight(h); setWidth(w); } void HorizontalLayout::relocateChildren() { int spaceBorder = (borderLines() != 0) ? borderLineSize() : 0; if (m_children.count()isVisible()){ item->setPos(curX,spaceBorder); curX+=item->width(); item->setHeight(height()-(spaceBorder * 2)); } } m_isRelocating = false; } void HorizontalLayout::beforeDelete() { m_children.clear(); #ifdef HAVE_QT5 foreach (QObject *item, children()) { #else foreach (QObject *item, QObject::children()) { #endif BaseDesignIntf *bdItem = dynamic_cast(item); if (bdItem) { bdItem->setParentItem(parentItem()); bdItem->setParent(parent()); bdItem->setVisible(true); bdItem->setPos(mapToParent(bdItem->pos())); bdItem->setFixedPos(false); bdItem->setPossibleResizeDirectionFlags(AllDirections); } } } void HorizontalLayout::updateItemSize(DataSourceManager* dataManager, RenderPass pass, int maxHeight) { m_isRelocating=true; ItemDesignIntf::updateItemSize(dataManager, pass, maxHeight); foreach(QGraphicsItem *child, childItems()){ BaseDesignIntf* item = dynamic_cast(child); if (item) item->updateItemSize(dataManager, pass, maxHeight); } updateLayoutSize(); relocateChildren(); m_isRelocating=false; BaseDesignIntf::updateItemSize(dataManager, pass, maxHeight); } bool HorizontalLayout::isNeedUpdateSize(RenderPass pass) const { foreach (QGraphicsItem *child, childItems()) { BaseDesignIntf* item = dynamic_cast(child); if (item && item->isNeedUpdateSize(pass)) return true; } return false; } void HorizontalLayout::childAddedEvent(BaseDesignIntf *child) { addChild(child,false); } void HorizontalLayout::slotOnChildDestroy(QObject* child) { m_children.removeAll(static_cast(child)); if (m_children.count()<2){ beforeDelete(); // deleteLater(); } else { relocateChildren(); updateLayoutSize(); } } BaseDesignIntf* HorizontalLayout::findNext(BaseDesignIntf* item){ if (m_children.count()i+1){ return m_children[i+1];} } return 0; } BaseDesignIntf* HorizontalLayout::findPrior(BaseDesignIntf* item){ if (m_children.count()width(); } qreal delta = (width() - itemsSumSize)/m_children.size(); for (int i=0; isetWidth(m_children[i]->width()+(delta)); if ((i+1)setPos(m_children[i+1]->pos().x()+delta*(i+1),m_children[i+1]->pos().y()); } m_isRelocating = false; } void HorizontalLayout::slotOnChildGeometryChanged(QObject *item, QRectF newGeometry, QRectF oldGeometry) { if (!m_isRelocating){ //setHeight(newGeometry.height()); if (m_layoutType == Layout){ relocateChildren(); updateLayoutSize(); } else { m_isRelocating = true; qreal delta = newGeometry.width()-oldGeometry.width(); BaseDesignIntf* resizingItem = findNext(dynamic_cast(item)); if (resizingItem) { resizingItem->setWidth(resizingItem->width()-delta); resizingItem->setPos(resizingItem->pos().x()+delta,resizingItem->pos().y()); } updateLayoutSize(); m_isRelocating = false; } } } void HorizontalLayout::slotOnChildItemAlignChanged(BaseDesignIntf *item, const BaseDesignIntf::ItemAlign &, const BaseDesignIntf::ItemAlign&) { item->setPossibleResizeDirectionFlags(ResizeBottom | ResizeRight); } void HorizontalLayout::slotOnChildVisibleHasChanged(BaseDesignIntf *) { relocateChildren(); if (m_layoutType == Table && !m_isRelocating){ divideSpace(); } } HorizontalLayout::LayoutType HorizontalLayout::layoutType() const { return m_layoutType; } void HorizontalLayout::setLayoutType(const LayoutType &layoutType) { if (m_layoutType != layoutType){ LayoutType oldValue = m_layoutType; m_layoutType = layoutType; notify("layoutType",oldValue,layoutType); } } LayoutMarker::LayoutMarker(HorizontalLayout *layout, QGraphicsItem *parent) :QGraphicsItem(parent), m_rect(0,0,30,30), m_color(Qt::red), m_layout(layout){ setFlag(QGraphicsItem::ItemIsMovable); } void LayoutMarker::paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) { painter->save(); painter->setOpacity(Const::LAYOUT_MARKER_OPACITY); painter->fillRect(boundingRect(),m_color); painter->setRenderHint(QPainter::Antialiasing); qreal size = (boundingRect().width()isSelected()){ painter->setOpacity(1); QRectF r = QRectF(0,0,size,size); painter->setBrush(Qt::white); painter->setPen(Qt::white); painter->drawEllipse(r.adjusted(5,5,-5,-5)); painter->setBrush(m_color); painter->drawEllipse(r.adjusted(7,7,-7,-7)); } painter->restore(); } void LayoutMarker::setHeight(qreal height) { if (m_rect.height()!=height){ prepareGeometryChange(); m_rect.setHeight(height); } } void LayoutMarker::setWidth(qreal width) { if (m_rect.width()!=width){ prepareGeometryChange(); m_rect.setWidth(width); } } void LayoutMarker::setColor(QColor color) { if (m_color!=color){ m_color = color; update(boundingRect()); } } void LayoutMarker::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button()==Qt::LeftButton) { if (!(event->modifiers() & Qt::ControlModifier)) m_layout->scene()->clearSelection(); m_layout->setSelected(true); //m_layout->setChildVisibility(false); update(0,0,boundingRect().width(),boundingRect().width()); } } } // namespace LimeReport