25#include <QApplication>
26#include <QDomDocument>
28#include <QGraphicsItem>
35#include "moc_qgslayoutmodel.cpp"
37using namespace Qt::StringLiterals;
40 : QAbstractItemModel(
parent )
64 if ( !
parent.isValid() && row == 0 )
66 return createIndex( row, column,
nullptr );
68 else if ( !
parent.isValid() && row >= 1 && row < mItemsInScene.size() + 1 )
71 return createIndex( row, column, mItemsInScene.at( row - 1 ) );
78void QgsLayoutModel::refreshItemsInScene()
80 mItemsInScene.clear();
82 const QList< QGraphicsItem * > items = mLayout->items();
89 mItemsInScene.push_back( item );
106 return mItemsInScene.size() + 1;
131 if ( !
index.isValid() )
142 case Qt::DisplayRole:
152 case Qt::DecorationRole:
175 case Qt::UserRole + 1:
177 return QVariant::fromValue( qobject_cast<QObject *>( item ) );
179 case Qt::TextAlignmentRole:
180 return static_cast<Qt::Alignment::Int
>( Qt::AlignLeft & Qt::AlignVCenter );
182 case Qt::CheckStateRole:
183 switch (
index.column() )
187 return item->isVisible() ? Qt::Checked : Qt::Unchecked;
190 return item->
isLocked() ? Qt::Checked : Qt::Unchecked;
204 if ( !
index.isValid() )
213 switch (
index.column() )
227 item->
setId( value.toString() );
238 case Qt::DisplayRole:
247 case Qt::DecorationRole:
261 case Qt::TextAlignmentRole:
262 return static_cast<Qt::Alignment::Int
>( Qt::AlignLeft & Qt::AlignVCenter );
265 return QAbstractItemModel::headerData( section, orientation, role );
271 return Qt::MoveAction;
277 types << u
"application/x-vnd.qgis.qgis.composeritemid"_s;
283 QMimeData *
mimeData =
new QMimeData();
284 QByteArray encodedData;
286 QDataStream stream( &encodedData, QIODevice::WriteOnly );
288 for (
const QModelIndex &
index : indexes )
297 QString text = item->
uuid();
302 mimeData->setData( u
"application/x-vnd.qgis.qgis.composeritemid"_s, encodedData );
308 return item1->zValue() > item2->zValue();
313 if ( column !=
ItemId && column != -1 )
318 if ( action == Qt::IgnoreAction )
323 if ( !
data->hasFormat( u
"application/x-vnd.qgis.qgis.composeritemid"_s ) )
333 int beginRow = row != -1 ? row :
rowCount( QModelIndex() );
335 QByteArray encodedData =
data->data( u
"application/x-vnd.qgis.qgis.composeritemid"_s );
336 QDataStream stream( &encodedData, QIODevice::ReadOnly );
337 QList<QgsLayoutItem *> droppedItems;
339 while ( !stream.atEnd() )
346 droppedItems << item;
350 if ( droppedItems.empty() )
365 QgsLayoutItem *itemBefore = mItemsInScene.at( beginRow - 1 );
366 destPos = mItemZList.indexOf( itemBefore );
371 destPos = mItemZList.size();
375 int insertPos = destPos;
378 int listPos = mItemZList.indexOf( item );
385 if ( listPos < destPos )
392 auto itemIt = droppedItems.begin();
393 for ( ; itemIt != droppedItems.end(); ++itemIt )
395 mItemZList.removeOne( *itemIt );
399 itemIt = droppedItems.begin();
400 for ( ; itemIt != droppedItems.end(); ++itemIt )
402 mItemZList.insert( insertPos, *itemIt );
406 rebuildSceneItemList();
408 mLayout->updateZValues(
true );
431void QgsLayoutModel::clear()
436 refreshItemsInScene();
440int QgsLayoutModel::zOrderListSize()
const
442 return mItemZList.size();
445void QgsLayoutModel::rebuildZList()
447 QList<QgsLayoutItem *> sortedList;
451 const QList<QGraphicsItem *> itemList = mLayout->items( Qt::DescendingOrder );
452 for ( QGraphicsItem *item : itemList )
454 if ( QgsLayoutItem *layoutItem =
dynamic_cast<QgsLayoutItem *
>( item ) )
458 sortedList.append( layoutItem );
463 mItemZList = sortedList;
464 rebuildSceneItemList();
468void QgsLayoutModel::rebuildSceneItemList()
473 const QList< QGraphicsItem * > items = mLayout->items();
474 for ( QgsLayoutItem *item : std::as_const( mItemZList ) )
482 int sceneListPos = mItemsInScene.indexOf( item );
483 if ( sceneListPos == row )
487 else if ( sceneListPos != -1 )
490 beginMoveRows( QModelIndex(), sceneListPos + 1, sceneListPos + 1, QModelIndex(), row + 1 );
491 mItemsInScene.removeAt( sceneListPos );
492 mItemsInScene.insert( row, item );
498 beginInsertRows( QModelIndex(), row + 1, row + 1 );
499 mItemsInScene.insert( row, item );
508 mItemZList.push_front( item );
509 refreshItemsInScene();
510 item->setZValue( mItemZList.size() );
521 int pos = mItemZList.indexOf( item );
530 if ( !itemIndex.isValid() )
535 mItemZList.removeAt( pos );
536 refreshItemsInScene();
541 int row = itemIndex.row();
542 beginRemoveRows( QModelIndex(), row, row );
543 mItemZList.removeAt( pos );
544 refreshItemsInScene();
556 int pos = mItemZList.indexOf( item );
565 if ( !itemIndex.isValid() )
571 int row = itemIndex.row();
572 beginRemoveRows( QModelIndex(), row, row );
573 mLayout->removeItem( item );
574 refreshItemsInScene();
578void QgsLayoutModel::updateItemDisplayName(
QgsLayoutItem *item )
588 if ( !itemIndex.isValid() )
594 emit dataChanged( itemIndex, itemIndex );
597void QgsLayoutModel::updateItemLockStatus(
QgsLayoutItem *item )
607 if ( !itemIndex.isValid() )
613 emit dataChanged( itemIndex, itemIndex );
616void QgsLayoutModel::updateItemVisibility(
QgsLayoutItem *item )
626 if ( !itemIndex.isValid() )
632 emit dataChanged( itemIndex, itemIndex );
635void QgsLayoutModel::updateItemSelectStatus(
QgsLayoutItem *item )
645 if ( !itemIndex.isValid() )
651 emit dataChanged( itemIndex, itemIndex );
661 if ( mItemsInScene.at( 0 ) == item )
668 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
669 if ( !it.findNext( item ) )
675 const QList< QGraphicsItem * > sceneItems = mLayout->items();
678 while ( it.hasPrevious() )
682 if ( it.value() && sceneItems.contains( it.value() ) )
691 if ( !itemIndex.isValid() )
697 int row = itemIndex.row();
698 beginMoveRows( QModelIndex(), row, row, QModelIndex(), row - 1 );
699 refreshItemsInScene();
711 if ( mItemsInScene.last() == item )
718 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
719 if ( !it.findNext( item ) )
725 const QList< QGraphicsItem * > sceneItems = mLayout->items();
727 while ( it.hasNext() )
733 if ( it.value() && sceneItems.contains( it.value() ) )
742 if ( !itemIndex.isValid() )
748 int row = itemIndex.row();
749 beginMoveRows( QModelIndex(), row, row, QModelIndex(), row + 2 );
750 refreshItemsInScene();
757 if ( !item || !mItemsInScene.contains( item ) )
762 if ( mItemsInScene.at( 0 ) == item )
769 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
770 if ( it.findNext( item ) )
774 mItemZList.push_front( item );
778 if ( !itemIndex.isValid() )
784 int row = itemIndex.row();
785 beginMoveRows( QModelIndex(), row, row, QModelIndex(), 1 );
786 refreshItemsInScene();
791bool QgsLayoutModel::reorderItemToBottom(
QgsLayoutItem *item )
793 if ( !item || !mItemsInScene.contains( item ) )
798 if ( mItemsInScene.last() == item )
805 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
806 if ( it.findNext( item ) )
810 mItemZList.push_back( item );
814 if ( !itemIndex.isValid() )
820 int row = itemIndex.row();
821 beginMoveRows( QModelIndex(), row, row, QModelIndex(),
rowCount() );
822 refreshItemsInScene();
830 QListIterator<QgsLayoutItem *> it( mItemZList );
832 if ( it.findPrevious( item ) )
835 while ( it.hasPrevious() )
838 if ( it.hasPrevious() && !it.peekPrevious()->isGroupMember() )
840 return it.previous();
851 QListIterator<QgsLayoutItem *> it( mItemZList );
852 if ( it.findNext( item ) )
855 while ( it.hasNext() )
857 if ( !it.peekNext()->isGroupMember() )
867QList<QgsLayoutItem *> &QgsLayoutModel::zOrderList()
876 Qt::ItemFlags
flags = QAbstractItemModel::flags(
index );
878 if ( !
index.isValid() )
880 return flags | Qt::ItemIsDropEnabled;
883 if (
index.row() == 0 )
885 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
889 switch (
index.column() )
893 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
895 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
897 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
906 return QModelIndex();
909 int row = mItemsInScene.indexOf( item );
913 return QModelIndex();
916 return index( row + 1, column );
920void QgsLayoutModel::setSelected(
const QModelIndex &index )
936 mLayout->setSelectedItem( item );
938 if ( group && group != item )
948 : QSortFilterProxyModel( parent )
952 setSourceModel( mLayout->itemsModel() );
954 setDynamicSortFilter(
true );
955 setSortLocaleAware(
true );
961 const QString leftText = sourceModel()->data( left, Qt::DisplayRole ).toString();
962 const QString rightText = sourceModel()->data( right, Qt::DisplayRole ).toString();
963 if ( leftText.isEmpty() )
965 if ( rightText.isEmpty() )
986 QVariant itemAsVariant = sourceModel()->data( sourceIndex, Qt::UserRole + 1 );
987 return qobject_cast<QgsLayoutItem *>( itemAsVariant.value<QObject *>() );
992 mAllowEmpty = allowEmpty;
1014 mItemTypeFilter = filter;
1020 if ( mExceptedList == items )
1023 mExceptedList = items;
1030 QModelIndex index = sourceModel()->index( sourceRow, 0, sourceParent );
1037 if ( mExceptedList.contains( item ) )
1044 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)