QGIS API Documentation 3.41.0-Master (cea29feecf2)
Loading...
Searching...
No Matches
qgslayoutitemslistview.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayoutitemslistview.cpp
3 --------------------------
4 Date : October 2017
5 Copyright : (C) 2017 Nyall Dawson
6 Email : nyall dot dawson at gmail dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
17#include "moc_qgslayoutitemslistview.cpp"
18#include "qgslayout.h"
19#include "qgslayoutmodel.h"
21#include "qgslayoutview.h"
22#include "qgslayoutitemgroup.h"
23#include <QHeaderView>
24#include <QMenu>
25#include <QMouseEvent>
26
27
29 : QSortFilterProxyModel( parent )
30 , mModel( model )
31{
32 setSourceModel( mModel );
33}
34
36{
37 return mModel->itemFromIndex( mapToSource( index ) );
38}
39
40QModelIndex QgsLayoutItemsListViewModel::indexForItem( QgsLayoutItem *item, const int column ) const
41{
42 return mapFromSource( mModel->indexForItem( item, column ) );
43}
44
45void QgsLayoutItemsListViewModel::setSelected( const QModelIndex &index )
46{
47 mModel->setSelected( mapToSource( index ) );
48}
49
50bool QgsLayoutItemsListViewModel::filterAcceptsRow( int sourceRow, const QModelIndex & ) const
51{
52 if ( sourceRow == 0 )
53 return false; // hide empty null item row
54 return true;
55}
56
57QVariant QgsLayoutItemsListViewModel::data( const QModelIndex &index, int role ) const
58{
59 if ( !index.isValid() )
60 return QVariant();
61
62 QgsLayoutItem *item = itemFromIndex( index );
63 if ( !item )
64 {
65 return QVariant();
66 }
67
68 if ( role == Qt::FontRole )
69 {
70 if ( index.column() == QgsLayoutModel::ItemId && item->isSelected() )
71 {
72 //draw name of selected items in bold
73 QFont boldFont;
74 boldFont.setBold( true );
75 return boldFont;
76 }
77 }
78
79 return QSortFilterProxyModel::data( index, role );
80}
81
82
83//
84// QgsLayoutItemsListView
85//
86
88 : QTreeView( parent )
89 , mDesigner( designer )
90{
91 setColumnWidth( 0, 30 );
92 setColumnWidth( 1, 30 );
93 setDragEnabled( true );
94 setAcceptDrops( true );
95 setDropIndicatorShown( true );
96 setDragDropMode( QAbstractItemView::InternalMove );
97 setContextMenuPolicy( Qt::CustomContextMenu );
98 setIndentation( 0 );
99
100 // Allow multi selection from the list view
101 setSelectionMode( QAbstractItemView::ExtendedSelection );
102 setSelectionBehavior( QAbstractItemView::SelectRows );
103
104 connect( this, &QWidget::customContextMenuRequested, this, &QgsLayoutItemsListView::showContextMenu );
105 connect( mDesigner->view(), &QgsLayoutView::itemFocused, this, &QgsLayoutItemsListView::onItemFocused );
106}
107
109{
110 mLayout = layout;
111 mModel = new QgsLayoutItemsListViewModel( layout->itemsModel(), this );
112 setModel( mModel );
113
114 header()->setSectionResizeMode( 0, QHeaderView::Fixed );
115 header()->setSectionResizeMode( 1, QHeaderView::Fixed );
116 setColumnWidth( 0, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'x' ) * 4 );
117 setColumnWidth( 1, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'x' ) * 4 );
118 header()->setSectionsMovable( false );
119
120 connect( selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsLayoutItemsListView::updateSelection );
121}
122
124{
125 if ( event->key() == Qt::Key_Space )
126 {
127 const auto constSelectedIndexes = selectionModel()->selectedIndexes();
128 if ( !constSelectedIndexes.isEmpty() )
129 {
130 const bool isFirstItemVisible = mModel->itemFromIndex( constSelectedIndexes[0] )->isVisible();
131
132 for ( const QModelIndex &index : constSelectedIndexes )
133 {
134 if ( QgsLayoutItem *item = mModel->itemFromIndex( index ) )
135 {
136 item->setVisibility( !isFirstItemVisible );
137 }
138 }
139 //return here, because otherwise it will just invert visibility for each item instead setting all the same
140 return;
141 }
142 }
143
144 QTreeView::keyPressEvent( event );
145}
146
147void QgsLayoutItemsListView::updateSelection()
148{
149 // Do nothing if we are currently updating the selection
150 // because user has selected/deselected some items in the
151 // graphics view
152 if ( !mModel || mUpdatingFromView )
153 return;
154
155 // Set the updating flag
156 mUpdatingSelection = true;
157
158 // Deselect all items from the layout (prevent firing signals, selection will be changed)
159 whileBlocking( mLayout )->deselectAll();
160
161 // Build the list of selected items
162 QList<QgsLayoutItem *> selectedItems;
163 for ( const QModelIndex &index : selectionModel()->selectedIndexes() )
164 {
165 if ( QgsLayoutItem *item = mModel->itemFromIndex( index ) )
166 {
167 selectedItems << item;
168 }
169 }
170
171
172 bool itemSelected = false;
173
174 // Check if the clicked item was selected or deselected
175 if ( selectionModel()->isSelected( selectionModel()->currentIndex() ) )
176 {
177 // It it was selected, set it as the layout's selected item;
178 // This will show the item properties
179 QgsLayoutItem *currentItem = mModel->itemFromIndex( selectionModel()->currentIndex() );
180 mLayout->setSelectedItem( currentItem );
181 itemSelected = true;
182 }
183 for ( QgsLayoutItem *item : selectedItems )
184 {
185 if ( !itemSelected )
186 {
187 // If clicked item was actually deselected, set the first selected item in the list
188 // as the layout's selected item
189 mLayout->setSelectedItem( item );
190 itemSelected = true;
191 }
192 else
193 {
194 item->setSelected( true );
195 }
196
197 // find top level group this item is contained within, and mark the group as selected
198 QgsLayoutItemGroup *group = item->parentGroup();
199 while ( group && group->parentGroup() )
200 {
201 group = group->parentGroup();
202 }
203 if ( group && group != item )
204 group->setSelected( true );
205 }
206 // Reset the updating flag
207 mUpdatingSelection = false;
208}
209
210void QgsLayoutItemsListView::onItemFocused( QgsLayoutItem *focusedItem )
211{
212 // Do nothing if we are in the middle of selecting items in the layoutView
213 if ( !mModel || mUpdatingSelection )
214 return;
215
216 // Set the updating flag
217 mUpdatingFromView = true;
218
219 // Deselect all items in list
220 clearSelection();
221
222 // Set the current index to the focused item
223 QModelIndex index = mModel->indexForItem( focusedItem );
224 if ( index.isValid() )
225 {
226 setCurrentIndex( index );
227 }
228
229 // Select rows in the item list for every selected items in the graphics view
230 const QList<QgsLayoutItem *> selectedItems = mLayout->selectedLayoutItems();
231 for ( QgsLayoutItem *item : selectedItems )
232 {
233 const QModelIndex firstCol = mModel->indexForItem( item );
234 if ( firstCol.isValid() )
235 {
236 // Select the whole row
237 QItemSelection selection;
238 selection.select( firstCol, firstCol.siblingAtColumn( mModel->columnCount( firstCol.parent() ) - 1 ) );
239 selectionModel()->select( selection, QItemSelectionModel::Select );
240 }
241 }
242 // Reset the updating flag
243 mUpdatingFromView = false;
244}
245
246void QgsLayoutItemsListView::showContextMenu( QPoint point )
247{
248 if ( !mModel )
249 return;
250 const QModelIndex index = indexAt( point );
251 QgsLayoutItem *item = mModel->itemFromIndex( index );
252 if ( !item )
253 return;
254
255 QMenu *menu = new QMenu( this );
256
257 QAction *copyAction = new QAction( tr( "Copy Item" ), menu );
258 connect( copyAction, &QAction::triggered, this, [this, item]() {
259 mDesigner->view()->copyItems( QList<QgsLayoutItem *>() << item, QgsLayoutView::ClipboardCopy );
260 } );
261 menu->addAction( copyAction );
262 QAction *deleteAction = new QAction( tr( "Delete Item" ), menu );
263 connect( deleteAction, &QAction::triggered, this, [this, item]() {
264 mDesigner->view()->deleteItems( QList<QgsLayoutItem *>() << item );
265 } );
266 menu->addAction( deleteAction );
267 menu->addSeparator();
268
269 QAction *itemPropertiesAction = new QAction( tr( "Item Properties…" ), menu );
270 connect( itemPropertiesAction, &QAction::triggered, this, [this, item]() {
271 mDesigner->showItemOptions( item, true );
272 } );
273 menu->addAction( itemPropertiesAction );
274
275 menu->popup( mapToGlobal( point ) );
276}
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:5733
A common interface for layout designer dialogs and widgets.
virtual void showItemOptions(QgsLayoutItem *item, bool bringPanelToFront=true)=0
Shows the configuration widget for the specified layout item.
virtual QgsLayoutView * view()=0
Returns the layout view utilized by the designer.
A container for grouping several QgsLayoutItems.
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 void setVisibility(bool visible)
Sets whether the item is visible.
Model for the layout items list view.
QgsLayoutItem * itemFromIndex(const QModelIndex &index) const
Returns the layout item listed at the specified index.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
QgsLayoutItemsListViewModel(QgsLayoutModel *model, QObject *parent)
constructor
void setSelected(const QModelIndex &index)
Sets the selected index.
QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const override
QModelIndex indexForItem(QgsLayoutItem *item, const int column=0) const
Returns the model index matching the specified layout item.
void setCurrentLayout(QgsLayout *layout)
Sets the current layout.
QgsLayoutItemsListView(QWidget *parent, QgsLayoutDesignerInterface *designer)
Constructor for QgsLayoutItemsListView.
void keyPressEvent(QKeyEvent *event) override
A model for items attached to a layout.
QgsLayoutItem * itemFromIndex(const QModelIndex &index) const
Returns the QgsLayoutItem corresponding to a QModelIndex index, if possible.
QModelIndex indexForItem(QgsLayoutItem *item, int column=0)
Returns the QModelIndex corresponding to a QgsLayoutItem item and column, if possible.
void itemFocused(QgsLayoutItem *item)
Emitted when an item is "focused" in the view, i.e.
@ ClipboardCopy
Copy items.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition qgslayout.h:49
QgsLayoutModel * itemsModel()
Returns the items model attached to the layout.
QList< QgsLayoutItem * > selectedLayoutItems(bool includeLockedItems=true)
Returns list of selected layout items.
void setSelectedItem(QgsLayoutItem *item)
Clears any selected items and sets item as the current selection.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:5928