QGIS API Documentation 3.41.0-Master (3440c17df1d)
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 }
207 // Reset the updating flag
208 mUpdatingSelection = false;
209}
210
211void QgsLayoutItemsListView::onItemFocused( QgsLayoutItem *focusedItem )
212{
213 // Do nothing if we are in the middle of selecting items in the layoutView
214 if ( !mModel || mUpdatingSelection )
215 return;
216
217 // Set the updating flag
218 mUpdatingFromView = true;
219
220 // Deselect all items in list
221 clearSelection();
222
223 // Set the current index to the focused item
224 QModelIndex index = mModel->indexForItem( focusedItem );
225 if ( index.isValid() )
226 {
227 setCurrentIndex( index );
228 }
229
230 // Select rows in the item list for every selected items in the graphics view
231 const QList< QgsLayoutItem *> selectedItems = mLayout->selectedLayoutItems();
232 for ( QgsLayoutItem *item : selectedItems )
233 {
234 const QModelIndex firstCol = mModel->indexForItem( item );
235 if ( firstCol.isValid() )
236 {
237 // Select the whole row
238 QItemSelection selection;
239 selection.select( firstCol, firstCol.siblingAtColumn( mModel->columnCount( firstCol.parent() ) - 1 ) );
240 selectionModel()->select( selection, QItemSelectionModel::Select );
241 }
242 }
243 // Reset the updating flag
244 mUpdatingFromView = false;
245}
246
247void QgsLayoutItemsListView::showContextMenu( QPoint point )
248{
249 if ( !mModel )
250 return;
251 const QModelIndex index = indexAt( point );
252 QgsLayoutItem *item = mModel->itemFromIndex( index );
253 if ( !item )
254 return;
255
256 QMenu *menu = new QMenu( this );
257
258 QAction *copyAction = new QAction( tr( "Copy Item" ), menu );
259 connect( copyAction, &QAction::triggered, this, [this, item]()
260 {
261 mDesigner->view()->copyItems( QList< QgsLayoutItem * >() << item, QgsLayoutView::ClipboardCopy );
262 } );
263 menu->addAction( copyAction );
264 QAction *deleteAction = new QAction( tr( "Delete Item" ), menu );
265 connect( deleteAction, &QAction::triggered, this, [this, item]()
266 {
267 mDesigner->view()->deleteItems( QList< QgsLayoutItem * >() << item );
268 } );
269 menu->addAction( deleteAction );
270 menu->addSeparator();
271
272 QAction *itemPropertiesAction = new QAction( tr( "Item Properties…" ), menu );
273 connect( itemPropertiesAction, &QAction::triggered, this, [this, item]()
274 {
275 mDesigner->showItemOptions( item, true );
276 } );
277 menu->addAction( itemPropertiesAction );
278
279 menu->popup( mapToGlobal( point ) );
280}
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:5667
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:5862