25#include <QApplication>
26#include <QDomDocument>
28#include <QGraphicsItem>
34#include "moc_qgslayoutmodel.cpp"
37 : QAbstractItemModel(
parent )
56 const QModelIndex &
parent )
const
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:
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 );
272 return Qt::MoveAction;
278 types << QStringLiteral(
"application/x-vnd.qgis.qgis.composeritemid" );
284 QMimeData *
mimeData =
new QMimeData();
285 QByteArray encodedData;
287 QDataStream stream( &encodedData, QIODevice::WriteOnly );
289 for (
const QModelIndex &
index : indexes )
298 QString text = item->
uuid();
303 mimeData->setData( QStringLiteral(
"application/x-vnd.qgis.qgis.composeritemid" ), encodedData );
309 return item1->zValue() > item2->zValue();
313 Qt::DropAction action,
int row,
int column,
const QModelIndex &
parent )
315 if ( column !=
ItemId && column != -1 )
320 if ( action == Qt::IgnoreAction )
325 if ( !
data->hasFormat( QStringLiteral(
"application/x-vnd.qgis.qgis.composeritemid" ) ) )
335 int beginRow = row != -1 ? row :
rowCount( QModelIndex() );
337 QByteArray encodedData =
data->data( QStringLiteral(
"application/x-vnd.qgis.qgis.composeritemid" ) );
338 QDataStream stream( &encodedData, QIODevice::ReadOnly );
339 QList<QgsLayoutItem *> droppedItems;
341 while ( !stream.atEnd() )
348 droppedItems << item;
352 if ( droppedItems.empty() )
367 QgsLayoutItem *itemBefore = mItemsInScene.at( beginRow - 1 );
368 destPos = mItemZList.indexOf( itemBefore );
373 destPos = mItemZList.size();
377 int insertPos = destPos;
380 int listPos = mItemZList.indexOf( item );
387 if ( listPos < destPos )
394 auto itemIt = droppedItems.begin();
395 for ( ; itemIt != droppedItems.end(); ++itemIt )
397 mItemZList.removeOne( *itemIt );
401 itemIt = droppedItems.begin();
402 for ( ; itemIt != droppedItems.end(); ++itemIt )
404 mItemZList.insert( insertPos, *itemIt );
408 rebuildSceneItemList();
410 mLayout->updateZValues(
true );
433void QgsLayoutModel::clear()
438 refreshItemsInScene();
442int QgsLayoutModel::zOrderListSize()
const
444 return mItemZList.size();
447void QgsLayoutModel::rebuildZList()
449 QList<QgsLayoutItem *> sortedList;
453 const QList<QGraphicsItem *> itemList = mLayout->items( Qt::DescendingOrder );
454 for ( QGraphicsItem *item : itemList )
456 if ( QgsLayoutItem *layoutItem =
dynamic_cast<QgsLayoutItem *
>( item ) )
460 sortedList.append( layoutItem );
465 mItemZList = sortedList;
466 rebuildSceneItemList();
470void QgsLayoutModel::rebuildSceneItemList()
475 const QList< QGraphicsItem * > items = mLayout->items();
476 for ( QgsLayoutItem *item : std::as_const( mItemZList ) )
484 int sceneListPos = mItemsInScene.indexOf( item );
485 if ( sceneListPos == row )
490 else if ( sceneListPos != -1 )
493 beginMoveRows( QModelIndex(), sceneListPos + 1, sceneListPos + 1, QModelIndex(), row + 1 );
494 mItemsInScene.removeAt( sceneListPos );
495 mItemsInScene.insert( row, item );
501 beginInsertRows( QModelIndex(), row + 1, row + 1 );
502 mItemsInScene.insert( row, item );
511 mItemZList.push_front( item );
512 refreshItemsInScene();
513 item->setZValue( mItemZList.size() );
524 int pos = mItemZList.indexOf( item );
533 if ( !itemIndex.isValid() )
538 mItemZList.removeAt( pos );
539 refreshItemsInScene();
544 int row = itemIndex.row();
545 beginRemoveRows( QModelIndex(), row, row );
546 mItemZList.removeAt( pos );
547 refreshItemsInScene();
559 int pos = mItemZList.indexOf( item );
568 if ( !itemIndex.isValid() )
574 int row = itemIndex.row();
575 beginRemoveRows( QModelIndex(), row, row );
576 mLayout->removeItem( item );
577 refreshItemsInScene();
581void QgsLayoutModel::updateItemDisplayName(
QgsLayoutItem *item )
591 if ( !itemIndex.isValid() )
597 emit dataChanged( itemIndex, itemIndex );
600void QgsLayoutModel::updateItemLockStatus(
QgsLayoutItem *item )
610 if ( !itemIndex.isValid() )
616 emit dataChanged( itemIndex, itemIndex );
619void QgsLayoutModel::updateItemVisibility(
QgsLayoutItem *item )
629 if ( !itemIndex.isValid() )
635 emit dataChanged( itemIndex, itemIndex );
638void QgsLayoutModel::updateItemSelectStatus(
QgsLayoutItem *item )
648 if ( !itemIndex.isValid() )
654 emit dataChanged( itemIndex, itemIndex );
664 if ( mItemsInScene.at( 0 ) == item )
671 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
672 if ( ! it.findNext( item ) )
678 const QList< QGraphicsItem * > sceneItems = mLayout->items();
681 while ( it.hasPrevious() )
685 if ( it.value() && sceneItems.contains( it.value() ) )
694 if ( !itemIndex.isValid() )
700 int row = itemIndex.row();
701 beginMoveRows( QModelIndex(), row, row, QModelIndex(), row - 1 );
702 refreshItemsInScene();
714 if ( mItemsInScene.last() == item )
721 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
722 if ( ! it.findNext( item ) )
728 const QList< QGraphicsItem * > sceneItems = mLayout->items();
730 while ( it.hasNext() )
736 if ( it.value() && sceneItems.contains( it.value() ) )
745 if ( !itemIndex.isValid() )
751 int row = itemIndex.row();
752 beginMoveRows( QModelIndex(), row, row, QModelIndex(), row + 2 );
753 refreshItemsInScene();
760 if ( !item || !mItemsInScene.contains( item ) )
765 if ( mItemsInScene.at( 0 ) == item )
772 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
773 if ( it.findNext( item ) )
777 mItemZList.push_front( item );
781 if ( !itemIndex.isValid() )
787 int row = itemIndex.row();
788 beginMoveRows( QModelIndex(), row, row, QModelIndex(), 1 );
789 refreshItemsInScene();
794bool QgsLayoutModel::reorderItemToBottom(
QgsLayoutItem *item )
796 if ( !item || !mItemsInScene.contains( item ) )
801 if ( mItemsInScene.last() == item )
808 QMutableListIterator<QgsLayoutItem *> it( mItemZList );
809 if ( it.findNext( item ) )
813 mItemZList.push_back( item );
817 if ( !itemIndex.isValid() )
823 int row = itemIndex.row();
824 beginMoveRows( QModelIndex(), row, row, QModelIndex(),
rowCount() );
825 refreshItemsInScene();
833 QListIterator<QgsLayoutItem *> it( mItemZList );
835 if ( it.findPrevious( item ) )
838 while ( it.hasPrevious() )
841 if ( it.hasPrevious() && !it.peekPrevious()->isGroupMember() )
843 return it.previous();
854 QListIterator<QgsLayoutItem *> it( mItemZList );
855 if ( it.findNext( item ) )
858 while ( it.hasNext() )
860 if ( !it.peekNext()->isGroupMember() )
870QList<QgsLayoutItem *> &QgsLayoutModel::zOrderList()
879 Qt::ItemFlags
flags = QAbstractItemModel::flags(
index );
881 if ( !
index.isValid() )
883 return flags | Qt::ItemIsDropEnabled;
886 if (
index.row() == 0 )
888 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
892 switch (
index.column() )
896 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
898 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
900 return flags | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
909 return QModelIndex();
912 int row = mItemsInScene.indexOf( item );
916 return QModelIndex();
919 return index( row + 1, column );
923void QgsLayoutModel::setSelected(
const QModelIndex &index )
939 mLayout->setSelectedItem( item );
941 if ( group && group != item )
951 : QSortFilterProxyModel( parent )
955 setSourceModel( mLayout->itemsModel() );
957 setDynamicSortFilter(
true );
958 setSortLocaleAware(
true );
964 const QString leftText = sourceModel()->data( left, Qt::DisplayRole ).toString();
965 const QString rightText = sourceModel()->data( right, Qt::DisplayRole ).toString();
966 if ( leftText.isEmpty() )
968 if ( rightText.isEmpty() )
989 QVariant itemAsVariant = sourceModel()->data( sourceIndex, Qt::UserRole + 1 );
990 return qobject_cast<QgsLayoutItem *>( itemAsVariant.value<QObject *>() );
995 mAllowEmpty = allowEmpty;
1017 mItemTypeFilter = filter;
1023 if ( mExceptedList == items )
1026 mExceptedList = items;
1033 QModelIndex index = sourceModel()->index( sourceRow, 0, sourceParent );
1040 if ( mExceptedList.contains( item ) )
1047 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)