25#include <QApplication>
26#include <QDomDocument>
28#include <QGraphicsItem>
35#include "moc_qgslayoutmodel.cpp"
37using namespace Qt::StringLiterals;
40 : QAbstractItemModel(
parent )
59 const QModelIndex &
parent )
const
67 if ( !
parent.isValid() && row == 0 )
69 return createIndex( row, column,
nullptr );
71 else if ( !
parent.isValid() && row >= 1 && row < mItemsInScene.size() + 1 )
74 return createIndex( row, column, mItemsInScene.at( row - 1 ) );
81void QgsLayoutModel::refreshItemsInScene()
83 mItemsInScene.clear();
85 const QList< QGraphicsItem * > items = mLayout->items();
92 mItemsInScene.push_back( item );
102 return QModelIndex();
109 return mItemsInScene.size() + 1;
134 if ( !
index.isValid() )
145 case Qt::DisplayRole:
155 case Qt::DecorationRole:
180 return QVariant::fromValue( qobject_cast<QObject *>( item ) );
182 case Qt::TextAlignmentRole:
183 return static_cast<Qt::Alignment::Int
>( Qt::AlignLeft & Qt::AlignVCenter );
185 case Qt::CheckStateRole:
186 switch (
index.column() )
190 return item->isVisible() ? Qt::Checked : Qt::Unchecked;
193 return item->
isLocked() ? Qt::Checked : Qt::Unchecked;
207 if ( !
index.isValid() )
216 switch (
index.column() )
230 item->
setId( value.toString() );
241 case Qt::DisplayRole:
250 case Qt::DecorationRole:
264 case Qt::TextAlignmentRole:
265 return static_cast<Qt::Alignment::Int
>( Qt::AlignLeft & Qt::AlignVCenter );
268 return QAbstractItemModel::headerData( section, orientation, role );
275 return Qt::MoveAction;
281 types << u
"application/x-vnd.qgis.qgis.composeritemid"_s;
287 QMimeData *
mimeData =
new QMimeData();
288 QByteArray encodedData;
290 QDataStream stream( &encodedData, QIODevice::WriteOnly );
292 for (
const QModelIndex &
index : indexes )
301 QString text = item->
uuid();
306 mimeData->setData( u
"application/x-vnd.qgis.qgis.composeritemid"_s, encodedData );
312 return item1->zValue() > item2->zValue();
316 Qt::DropAction action,
int row,
int column,
const QModelIndex &
parent )
318 if ( column !=
ItemId && column != -1 )
323 if ( action == Qt::IgnoreAction )
328 if ( !
data->hasFormat( u
"application/x-vnd.qgis.qgis.composeritemid"_s ) )
338 int beginRow = row != -1 ? row :
rowCount( QModelIndex() );
340 QByteArray encodedData =
data->data( u
"application/x-vnd.qgis.qgis.composeritemid"_s );
341 QDataStream stream( &encodedData, QIODevice::ReadOnly );
342 QList<QgsLayoutItem *> droppedItems;
344 while ( !stream.atEnd() )
351 droppedItems << item;
355 if ( droppedItems.empty() )
370 QgsLayoutItem *itemBefore = mItemsInScene.at( beginRow - 1 );
371 destPos = mItemZList.indexOf( itemBefore );
376 destPos = mItemZList.size();
380 int insertPos = destPos;
383 int listPos = mItemZList.indexOf( item );
390 if ( listPos < destPos )
397 auto itemIt = droppedItems.begin();
398 for ( ; itemIt != droppedItems.end(); ++itemIt )
400 mItemZList.removeOne( *itemIt );
404 itemIt = droppedItems.begin();
405 for ( ; itemIt != droppedItems.end(); ++itemIt )
407 mItemZList.insert( insertPos, *itemIt );
411 rebuildSceneItemList();
413 mLayout->updateZValues(
true );
436void QgsLayoutModel::clear()
441 refreshItemsInScene();
445int QgsLayoutModel::zOrderListSize()
const
447 return mItemZList.size();
450void QgsLayoutModel::rebuildZList()
452 QList<QgsLayoutItem *> sortedList;
456 const QList<QGraphicsItem *> itemList = mLayout->items( Qt::DescendingOrder );
457 for ( QGraphicsItem *item : itemList )
459 if ( QgsLayoutItem *layoutItem =
dynamic_cast<QgsLayoutItem *
>( item ) )
463 sortedList.append( layoutItem );
468 mItemZList = sortedList;
469 rebuildSceneItemList();
473void QgsLayoutModel::rebuildSceneItemList()
478 const QList< QGraphicsItem * > items = mLayout->items();
479 for ( QgsLayoutItem *item : std::as_const( mItemZList ) )
487 int sceneListPos = mItemsInScene.indexOf( item );
488 if ( sceneListPos == row )
493 else if ( sceneListPos != -1 )
496 beginMoveRows( QModelIndex(), sceneListPos + 1, sceneListPos + 1, QModelIndex(), row + 1 );
497 mItemsInScene.removeAt( sceneListPos );
498 mItemsInScene.insert( row, item );
504 beginInsertRows( QModelIndex(), row + 1, row + 1 );
505 mItemsInScene.insert( row, item );
514 mItemZList.push_front( item );
515 refreshItemsInScene();
516 item->setZValue( mItemZList.size() );
527 int pos = mItemZList.indexOf( item );
536 if ( !itemIndex.isValid() )
541 mItemZList.removeAt( pos );
542 refreshItemsInScene();
547 int row = itemIndex.row();
548 beginRemoveRows( QModelIndex(), row, row );
549 mItemZList.removeAt( pos );
550 refreshItemsInScene();
562 int pos = mItemZList.indexOf( item );
571 if ( !itemIndex.isValid() )
577 int row = itemIndex.row();
578 beginRemoveRows( QModelIndex(), row, row );
579 mLayout->removeItem( item );
580 refreshItemsInScene();
584void QgsLayoutModel::updateItemDisplayName(
QgsLayoutItem *item )
594 if ( !itemIndex.isValid() )
600 emit dataChanged( itemIndex, itemIndex );
603void QgsLayoutModel::updateItemLockStatus(
QgsLayoutItem *item )
613 if ( !itemIndex.isValid() )
619 emit dataChanged( itemIndex, itemIndex );
622void QgsLayoutModel::updateItemVisibility(
QgsLayoutItem *item )
632 if ( !itemIndex.isValid() )
638 emit dataChanged( itemIndex, itemIndex );
641void QgsLayoutModel::updateItemSelectStatus(
QgsLayoutItem *item )
651 if ( !itemIndex.isValid() )
657 emit dataChanged( itemIndex, itemIndex );
667 if ( mItemsInScene.at( 0 ) == item )
674 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
675 if ( ! it.findNext( item ) )
681 const QList< QGraphicsItem * > sceneItems = mLayout->items();
684 while ( it.hasPrevious() )
688 if ( it.value() && sceneItems.contains( it.value() ) )
697 if ( !itemIndex.isValid() )
703 int row = itemIndex.row();
704 beginMoveRows( QModelIndex(), row, row, QModelIndex(), row - 1 );
705 refreshItemsInScene();
717 if ( mItemsInScene.last() == item )
724 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
725 if ( ! it.findNext( item ) )
731 const QList< QGraphicsItem * > sceneItems = mLayout->items();
733 while ( it.hasNext() )
739 if ( it.value() && sceneItems.contains( it.value() ) )
748 if ( !itemIndex.isValid() )
754 int row = itemIndex.row();
755 beginMoveRows( QModelIndex(), row, row, QModelIndex(), row + 2 );
756 refreshItemsInScene();
763 if ( !item || !mItemsInScene.contains( item ) )
768 if ( mItemsInScene.at( 0 ) == item )
775 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
776 if ( it.findNext( item ) )
780 mItemZList.push_front( item );
784 if ( !itemIndex.isValid() )
790 int row = itemIndex.row();
791 beginMoveRows( QModelIndex(), row, row, QModelIndex(), 1 );
792 refreshItemsInScene();
797bool QgsLayoutModel::reorderItemToBottom(
QgsLayoutItem *item )
799 if ( !item || !mItemsInScene.contains( item ) )
804 if ( mItemsInScene.last() == item )
811 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
812 if ( it.findNext( item ) )
816 mItemZList.push_back( item );
820 if ( !itemIndex.isValid() )
826 int row = itemIndex.row();
827 beginMoveRows( QModelIndex(), row, row, QModelIndex(),
rowCount() );
828 refreshItemsInScene();
836 QListIterator<QgsLayoutItem *> it( mItemZList );
838 if ( it.findPrevious( item ) )
841 while ( it.hasPrevious() )
844 if ( it.hasPrevious() && !it.peekPrevious()->isGroupMember() )
846 return it.previous();
857 QListIterator<QgsLayoutItem *> it( mItemZList );
858 if ( it.findNext( item ) )
861 while ( it.hasNext() )
863 if ( !it.peekNext()->isGroupMember() )
873QList<QgsLayoutItem *> &QgsLayoutModel::zOrderList()
882 Qt::ItemFlags
flags = QAbstractItemModel::flags(
index );
884 if ( !
index.isValid() )
886 return flags | Qt::ItemIsDropEnabled;
889 if (
index.row() == 0 )
891 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
895 switch (
index.column() )
899 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
901 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
903 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
912 return QModelIndex();
915 int row = mItemsInScene.indexOf( item );
919 return QModelIndex();
922 return index( row + 1, column );
926void QgsLayoutModel::setSelected(
const QModelIndex &index )
942 mLayout->setSelectedItem( item );
944 if ( group && group != item )
954 : QSortFilterProxyModel( parent )
958 setSourceModel( mLayout->itemsModel() );
960 setDynamicSortFilter(
true );
961 setSortLocaleAware(
true );
967 const QString leftText = sourceModel()->data( left, Qt::DisplayRole ).toString();
968 const QString rightText = sourceModel()->data( right, Qt::DisplayRole ).toString();
969 if ( leftText.isEmpty() )
971 if ( rightText.isEmpty() )
992 QVariant itemAsVariant = sourceModel()->data( sourceIndex, Qt::UserRole + 1 );
993 return qobject_cast<QgsLayoutItem *>( itemAsVariant.value<QObject *>() );
998 mAllowEmpty = allowEmpty;
1020 mItemTypeFilter = filter;
1026 if ( mExceptedList == items )
1029 mExceptedList = items;
1036 QModelIndex index = sourceModel()->index( sourceRow, 0, sourceParent );
1043 if ( mExceptedList.contains( item ) )
1050 if ( mItemFlags && !( item->
itemFlags() & mItemFlags ) )
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
@ LayoutItem
Base class for items.
Base class for graphical items within a QgsLayout.
QgsLayoutItemGroup * parentGroup() const
Returns the item's parent group, if the item is part of a QgsLayoutItemGroup group.
virtual void setSelected(bool selected)
Sets whether the item should be selected.
virtual QIcon icon() const
Returns the item's icon.
bool isLocked() const
Returns true if the item is locked, and cannot be interacted with using the mouse.
virtual void setVisibility(bool visible)
Sets whether the item is visible.
virtual void setId(const QString &id)
Set the item's id name.
void setLocked(bool locked)
Sets whether the item is locked, preventing mouse interactions with the item.
int type() const override
Returns a unique graphics item type identifier.
virtual QString displayName() const
Gets item display name.
virtual QString uuid() const
Returns the item identification string.
QString id() const
Returns the item's ID name.
virtual Flags itemFlags() const
Returns the item's flags, which indicate how the item behaves.
QMimeData * mimeData(const QModelIndexList &indexes) const override
QModelIndex parent(const QModelIndex &index) const override
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
bool removeRows(int row, int count, const QModelIndex &parent=QModelIndex()) override
QVariant data(const QModelIndex &index, int role) const override
QgsLayoutModel(QgsLayout *layout, QObject *parent=nullptr)
Constructor for a QgsLayoutModel attached to the specified layout.
QgsLayoutItem * itemFromIndex(const QModelIndex &index) const
Returns the QgsLayoutItem corresponding to a QModelIndex index, if possible.
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
Qt::DropActions supportedDropActions() const override
@ Visibility
Item visibility checkbox.
@ LockStatus
Item lock status checkbox.
QModelIndex indexForItem(QgsLayoutItem *item, int column=0)
Returns the QModelIndex corresponding to a QgsLayoutItem item and column, if possible.
QStringList mimeTypes() const override
Qt::ItemFlags flags(const QModelIndex &index) const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
int columnCount(const QModelIndex &parent=QModelIndex()) const override
int rowCount(const QModelIndex &parent=QModelIndex()) const override
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
void setExceptedItemList(const QList< QgsLayoutItem * > &items)
Sets a list of specific items to exclude from the model.
QgsLayoutItem::Flags itemFlags() const
Returns the layout item flags used for filtering the available items.
void setFilterType(QgsLayoutItemRegistry::ItemType filter)
Sets the item type filter.
bool allowEmptyItem() const
Returns true if the model includes the empty item choice.
void setItemFlags(QgsLayoutItem::Flags flags)
Sets layout item flags to use for filtering the available items.
void setAllowEmptyItem(bool allowEmpty)
Sets whether an optional empty layout item is present in the model.
QgsLayoutItem * itemFromSourceIndex(const QModelIndex &sourceIndex) const
Returns the QgsLayoutItem corresponding to an index from the source QgsLayoutModel model.
QgsLayoutProxyModel(QgsLayout *layout, QObject *parent=nullptr)
Constructor for QgsLayoutProxyModelm, attached to the specified layout.
QgsLayout * layout()
Returns the associated layout.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
bool zOrderDescending(QgsLayoutItem *item1, QgsLayoutItem *item2)