mirror of
https://github.com/python-LimeReport/LimeReport.git
synced 2024-12-23 20:22:58 +03:00
433 lines
12 KiB
C++
433 lines
12 KiB
C++
#include "lrabstractlayout.h"
|
|
|
|
namespace LimeReport {
|
|
|
|
AbstractLayout::AbstractLayout(QString xmlTag, QObject* owner, QGraphicsItem* parent)
|
|
: LayoutDesignIntf(xmlTag, owner, parent), m_isRelocating(false), m_layoutType(Layout),
|
|
m_hideEmptyItems(false), m_layoutSpacing(0)
|
|
{
|
|
setPossibleResizeDirectionFlags(AllDirections);
|
|
m_layoutMarker = new LayoutMarker(this);
|
|
m_layoutMarker->setParentItem(this);
|
|
m_layoutMarker->setColor(Qt::red);
|
|
m_layoutMarker->setHeight(height());
|
|
m_layoutMarker->setZValue(1);
|
|
}
|
|
|
|
AbstractLayout::~AbstractLayout()
|
|
{
|
|
if (m_layoutMarker) {
|
|
delete m_layoutMarker; m_layoutMarker=0;
|
|
}
|
|
}
|
|
|
|
QList<BaseDesignIntf*>& AbstractLayout::layoutsChildren()
|
|
{
|
|
return m_children;
|
|
}
|
|
|
|
bool AbstractLayout::isRelocating() const
|
|
{
|
|
return m_isRelocating;
|
|
}
|
|
|
|
void AbstractLayout::setIsRelocating(bool isRelocating)
|
|
{
|
|
m_isRelocating = isRelocating;
|
|
}
|
|
|
|
AbstractLayout::LayoutType AbstractLayout::layoutType() const
|
|
{
|
|
return m_layoutType;
|
|
}
|
|
|
|
void AbstractLayout::setLayoutType(const LayoutType& layoutType)
|
|
{
|
|
m_layoutType = layoutType;
|
|
}
|
|
|
|
void AbstractLayout::addChild(BaseDesignIntf* item, bool updateSize)
|
|
{
|
|
if (updateSize) placeItemInLayout(item);
|
|
|
|
m_children.append(item);
|
|
item->setParentItem(this);
|
|
item->setParent(this);
|
|
item->setFixedPos(true);
|
|
item->setPossibleResizeDirectionFlags(ResizeRight | ResizeBottom);
|
|
|
|
connectToLayout(item);
|
|
|
|
if (updateSize){
|
|
relocateChildren();
|
|
updateLayoutSize();
|
|
}
|
|
}
|
|
|
|
void AbstractLayout::removeChild(BaseDesignIntf *item)
|
|
{
|
|
if (!item) {
|
|
return;
|
|
}
|
|
m_children.removeAll(item);
|
|
disconnectFromLayout(item);
|
|
}
|
|
|
|
void AbstractLayout::restoreChild(BaseDesignIntf* item)
|
|
{
|
|
if (m_children.contains(item)) return;
|
|
m_isRelocating=true;
|
|
|
|
insertItemInLayout(item);
|
|
|
|
connectToLayout(item);
|
|
|
|
item->setFixedPos(true);
|
|
item->setPossibleResizeDirectionFlags(ResizeRight | ResizeBottom);
|
|
item->setParent(this);
|
|
item->setParentItem(this);
|
|
|
|
updateLayoutSize();
|
|
m_isRelocating=false;
|
|
}
|
|
|
|
bool AbstractLayout::isEmpty() const
|
|
{
|
|
bool isEmpty = true;
|
|
bool allItemsIsText = true;
|
|
foreach (QGraphicsItem* qgItem, childItems()) {
|
|
ContentItemDesignIntf* item = dynamic_cast<ContentItemDesignIntf*>(qgItem);
|
|
if (item && !item->content().isEmpty()) isEmpty = false;
|
|
if (!item && dynamic_cast<BaseDesignIntf*>(qgItem))
|
|
allItemsIsText = false;
|
|
}
|
|
return (isEmpty && allItemsIsText);
|
|
}
|
|
|
|
void AbstractLayout::paintChild(BaseDesignIntf *child, QPointF parentPos, QPainter *painter)
|
|
{
|
|
if (!child->childBaseItems().isEmpty()){
|
|
foreach (BaseDesignIntf* item, child->childBaseItems()) {
|
|
paintChild(item, child->pos(),painter);
|
|
}
|
|
}
|
|
painter->drawRect(
|
|
QRectF(parentPos.x()+child->pos().x(), parentPos.y()+child->pos().y(),
|
|
child->rect().bottomRight().rx(),
|
|
child->rect().bottomRight().ry()
|
|
)
|
|
);
|
|
}
|
|
|
|
void AbstractLayout::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
|
{
|
|
if (isSelected()){
|
|
painter->save();
|
|
painter->setPen(Qt::red);
|
|
foreach( BaseDesignIntf* item, m_children){
|
|
paintChild(item, QPointF(0,0), painter);
|
|
}
|
|
painter->restore();
|
|
}
|
|
LayoutDesignIntf::paint(painter, option, widget);
|
|
}
|
|
|
|
int AbstractLayout::childrenCount()
|
|
{
|
|
return m_children.size();
|
|
}
|
|
|
|
void AbstractLayout::beforeDelete()
|
|
{
|
|
#ifdef HAVE_QT5
|
|
foreach (QObject *item, children()) {
|
|
#else
|
|
foreach (QObject *item, QObject::children()) {
|
|
#endif
|
|
BaseDesignIntf *bi = dynamic_cast<BaseDesignIntf*>(item);
|
|
if (bi) {
|
|
bi->disconnect(this);
|
|
bi->setParentItem(parentItem());
|
|
bi->setParent(parent());
|
|
bi->setVisible(true);
|
|
bi->setPos(mapToParent(bi->pos()));
|
|
bi->setFixedPos(false);
|
|
bi->setPossibleResizeDirectionFlags(AllDirections);
|
|
}
|
|
}
|
|
m_children.clear();
|
|
}
|
|
|
|
void AbstractLayout::childAddedEvent(BaseDesignIntf* child)
|
|
{
|
|
addChild(child,false);
|
|
}
|
|
|
|
void AbstractLayout::geometryChangedEvent(QRectF newRect, QRectF)
|
|
{
|
|
layoutMarker()->setHeight(newRect.height());
|
|
relocateChildren();
|
|
if (!isRelocating()){
|
|
divideSpace();
|
|
}
|
|
}
|
|
|
|
void AbstractLayout::initMode(BaseDesignIntf::ItemMode mode)
|
|
{
|
|
BaseDesignIntf::initMode(mode);
|
|
if ((mode==PreviewMode)||(mode==PrintMode)){
|
|
layoutMarker()->setVisible(false);
|
|
} else {
|
|
layoutMarker()->setVisible(true);
|
|
}
|
|
}
|
|
|
|
void AbstractLayout::setBorderLinesFlags(BaseDesignIntf::BorderLines flags)
|
|
{
|
|
BaseDesignIntf::setBorderLinesFlags(flags);
|
|
if (flags!=0)
|
|
relocateChildren();
|
|
}
|
|
|
|
void AbstractLayout::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<BaseDesignIntf*>(obj);
|
|
if (item) {
|
|
addChild(item,false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AbstractLayout::objectLoadFinished()
|
|
{
|
|
layoutMarker()->setHeight(height());
|
|
LayoutDesignIntf::objectLoadFinished();
|
|
}
|
|
|
|
bool AbstractLayout::isNeedUpdateSize(RenderPass pass) const
|
|
{
|
|
Q_UNUSED(pass)
|
|
return true;
|
|
}
|
|
|
|
QVariant AbstractLayout::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant& value)
|
|
{
|
|
if (change == QGraphicsItem::ItemSelectedHasChanged){
|
|
setIsRelocating(true);
|
|
foreach(BaseDesignIntf* item, layoutsChildren()){
|
|
item->setVisible(!value.toBool());
|
|
}
|
|
setIsRelocating(false);
|
|
}
|
|
return LayoutDesignIntf::itemChange(change, value);
|
|
}
|
|
|
|
void AbstractLayout::updateItemSize(DataSourceManager* dataManager, RenderPass pass, int maxHeight)
|
|
{
|
|
setIsRelocating(true);
|
|
ItemDesignIntf::updateItemSize(dataManager, pass, maxHeight);
|
|
foreach(QGraphicsItem *child, childItems()){
|
|
BaseDesignIntf* item = dynamic_cast<BaseDesignIntf*>(child);
|
|
if (item && item->isNeedUpdateSize(pass))
|
|
item->updateItemSize(dataManager, pass, maxHeight);
|
|
}
|
|
updateLayoutSize();
|
|
relocateChildren();
|
|
setIsRelocating(false);
|
|
BaseDesignIntf::updateItemSize(dataManager, pass, maxHeight);
|
|
}
|
|
|
|
void AbstractLayout::rebuildChildrenIfNeeded(){
|
|
if (layoutsChildren().count() < childItems().size()-1){
|
|
layoutsChildren().clear();
|
|
foreach (BaseDesignIntf* childItem, childBaseItems()) {
|
|
layoutsChildren().append(childItem);
|
|
}
|
|
sortChildren();
|
|
}
|
|
}
|
|
|
|
void AbstractLayout::connectToLayout(BaseDesignIntf *item)
|
|
{
|
|
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*))
|
|
);
|
|
connect(
|
|
item, SIGNAL(itemSelectedHasBeenChanged(BaseDesignIntf*,bool)),
|
|
this, SLOT(slotOnChildSelectionHasChanged(BaseDesignIntf*,bool))
|
|
);
|
|
connect(
|
|
item, SIGNAL(itemAlignChanged(BaseDesignIntf*, const ItemAlign&, const ItemAlign&)),
|
|
this, SLOT(slotOnChildItemAlignChanged(BaseDesignIntf*,const ItemAlign&,const ItemAlign&))
|
|
);
|
|
}
|
|
|
|
void AbstractLayout::disconnectFromLayout(BaseDesignIntf *item)
|
|
{
|
|
disconnect(
|
|
item, SIGNAL(destroyed(QObject*)),
|
|
this, SLOT(slotOnChildDestroy(QObject*))
|
|
);
|
|
disconnect(
|
|
item,SIGNAL(geometryChanged(QObject*,QRectF,QRectF)),
|
|
this,SLOT(slotOnChildGeometryChanged(QObject*,QRectF,QRectF))
|
|
);
|
|
disconnect(
|
|
item, SIGNAL(itemVisibleHasChanged(BaseDesignIntf*)),
|
|
this, SLOT(slotOnChildVisibleHasChanged(BaseDesignIntf*))
|
|
);
|
|
disconnect(
|
|
item, SIGNAL(itemSelectedHasBeenChanged(BaseDesignIntf*,bool)),
|
|
this, SLOT(slotOnChildSelectionHasChanged(BaseDesignIntf*,bool))
|
|
);
|
|
disconnect(
|
|
item, SIGNAL(itemAlignChanged(BaseDesignIntf*, const ItemAlign&, const ItemAlign&)),
|
|
this, SLOT(slotOnChildItemAlignChanged(BaseDesignIntf*,const ItemAlign&,const ItemAlign&))
|
|
);
|
|
}
|
|
|
|
BaseDesignIntf *AbstractLayout::findNext(BaseDesignIntf *item)
|
|
{
|
|
rebuildChildrenIfNeeded();
|
|
for (int i=0; i<layoutsChildren().count();++i){
|
|
if (layoutsChildren()[i]==item && layoutsChildren().size()>i+1){ return layoutsChildren()[i+1];}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BaseDesignIntf *AbstractLayout::findPrior(BaseDesignIntf *item)
|
|
{
|
|
rebuildChildrenIfNeeded();
|
|
for (int i=0; i<layoutsChildren().count();++i){
|
|
if (layoutsChildren()[i]==item && i!=0){ return layoutsChildren()[i-1];}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void AbstractLayout::insertItemInLayout(BaseDesignIntf *item){
|
|
bool inserted = false;
|
|
for (int i=0; i<layoutsChildren().length(); ++i){
|
|
BaseDesignIntf* child = layoutsChildren()[i];
|
|
if (child->pos() == item->pos()){
|
|
layoutsChildren().insert(i, item);
|
|
inserted = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!inserted) layoutsChildren().append(item);
|
|
}
|
|
|
|
void AbstractLayout::slotOnChildDestroy(QObject* child)
|
|
{
|
|
m_children.removeAll(static_cast<BaseDesignIntf*>(child));
|
|
if (m_children.count() < 2 && !static_cast<LayoutDesignIntf*>(child)){
|
|
beforeDelete();
|
|
} else {
|
|
relocateChildren();
|
|
updateLayoutSize();
|
|
}
|
|
}
|
|
|
|
void AbstractLayout::slotOnChildGeometryChanged(QObject* item, QRectF newGeometry, QRectF oldGeometry)
|
|
{
|
|
if (!m_isRelocating && !isLoading()){
|
|
if (m_layoutType == Layout){
|
|
relocateChildren();
|
|
updateLayoutSize();
|
|
} else {
|
|
m_isRelocating = true;
|
|
qreal delta = newGeometry.width()-oldGeometry.width();
|
|
BaseDesignIntf* resizingItem = findNext(dynamic_cast<BaseDesignIntf*>(item));
|
|
if (resizingItem) {
|
|
resizingItem->setWidth(resizingItem->width()-delta);
|
|
resizingItem->setPos(resizingItem->pos().x()+delta,resizingItem->pos().y());
|
|
}
|
|
updateLayoutSize();
|
|
m_isRelocating = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
void AbstractLayout::slotOnChildItemAlignChanged(BaseDesignIntf* item, const ItemAlign&, const ItemAlign&)
|
|
{
|
|
item->setPossibleResizeDirectionFlags(ResizeBottom | ResizeRight);
|
|
}
|
|
|
|
void AbstractLayout::slotOnChildVisibleHasChanged(BaseDesignIntf*)
|
|
{
|
|
relocateChildren();
|
|
if (m_layoutType == Table && !m_isRelocating){
|
|
divideSpace();
|
|
}
|
|
}
|
|
|
|
void AbstractLayout::slotOnChildSelectionHasChanged(BaseDesignIntf* item, bool value)
|
|
{
|
|
item->setZValue(value ? item->zValue()+1 : item->zValue()-1);
|
|
}
|
|
|
|
int AbstractLayout::layoutSpacing() const
|
|
{
|
|
return m_layoutSpacing;
|
|
}
|
|
|
|
void AbstractLayout::setLayoutSpacing(int layoutSpacing)
|
|
{
|
|
if (m_layoutSpacing != layoutSpacing){
|
|
int oldValue = m_layoutSpacing;
|
|
m_layoutSpacing = layoutSpacing;
|
|
if (!isLoading()){
|
|
int delta = (m_layoutSpacing - oldValue) * (m_children.count()-1);
|
|
notify("layoutSpacing", oldValue, m_layoutSpacing);
|
|
setWidth(width() + delta);
|
|
}
|
|
relocateChildren();
|
|
}
|
|
}
|
|
|
|
bool AbstractLayout::hideEmptyItems() const
|
|
{
|
|
return m_hideEmptyItems;
|
|
}
|
|
|
|
void AbstractLayout::setHideEmptyItems(bool hideEmptyItems)
|
|
{
|
|
m_hideEmptyItems = hideEmptyItems;
|
|
|
|
if (m_hideEmptyItems != hideEmptyItems){
|
|
m_hideEmptyItems = hideEmptyItems;
|
|
notify("hideEmptyItems", !m_hideEmptyItems, m_hideEmptyItems);
|
|
}
|
|
}
|
|
|
|
QObject* AbstractLayout::at(int index)
|
|
{
|
|
rebuildChildrenIfNeeded();
|
|
if (layoutsChildren().size() > index) return layoutsChildren()[index];
|
|
return 0;
|
|
}
|
|
|
|
LayoutMarker* AbstractLayout::layoutMarker() const
|
|
{
|
|
return m_layoutMarker;
|
|
}
|
|
|
|
} // namespace LimeReport
|