QGIS API Documentation 3.99.0-Master (21b3aa880ba)
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
18#include "qgslayout.h"
20#include "qgslayoutitemgroup.h"
21#include "qgslayoutmodel.h"
22#include "qgslayoutview.h"
23
24#include <QHeaderView>
25#include <QMenu>
26#include <QMouseEvent>
27
28#include "moc_qgslayoutitemslistview.cpp"
29
31 : QSortFilterProxyModel( parent )
32 , mModel( model )
33{
34 setSourceModel( mModel );
35}
36
38{
39 return mModel->itemFromIndex( mapToSource( index ) );
40}
41
42QModelIndex QgsLayoutItemsListViewModel::indexForItem( QgsLayoutItem *item, const int column ) const
43{
44 return mapFromSource( mModel->indexForItem( item, column ) );
45}
46
47void QgsLayoutItemsListViewModel::setSelected( const QModelIndex &index )
48{
49 mModel->setSelected( mapToSource( index ) );
50}
51
52bool QgsLayoutItemsListViewModel::filterAcceptsRow( int sourceRow, const QModelIndex & ) const
53{
54 if ( sourceRow == 0 )
55 return false; // hide empty null item row
56 return true;
57}
58
59QVariant QgsLayoutItemsListViewModel::data( const QModelIndex &index, int role ) const
60{
61 if ( !index.isValid() )
62 return QVariant();
63
64 QgsLayoutItem *item = itemFromIndex( index );
65 if ( !item )
66 {
67 return QVariant();
68 }
69
70 if ( role == Qt::FontRole )
71 {
72 if ( index.column() == QgsLayoutModel::ItemId && item->isSelected() )
73 {
74 //draw name of selected items in bold
75 QFont boldFont;
76 boldFont.setBold( true );
77 return boldFont;
78 }
79 }
80
81 return QSortFilterProxyModel::data( index, role );
82}
83
84
85//
86// QgsLayoutItemsListView
87//
88
90 : QTreeView( parent )
91 , mDesigner( designer )
92{
93 setColumnWidth( 0, 30 );
94 setColumnWidth( 1, 30 );
95 setDragEnabled( true );
96 setAcceptDrops( true );
97 setDropIndicatorShown( true );
98 setDragDropMode( QAbstractItemView::InternalMove );
99 setContextMenuPolicy( Qt::CustomContextMenu );
100 setIndentation( 0 );
101
102 // Allow multi selection from the list view
103 setSelectionMode( QAbstractItemView::ExtendedSelection );
104 setSelectionBehavior( QAbstractItemView::SelectRows );
105
106 connect( this, &QWidget::customContextMenuRequested, this, &QgsLayoutItemsListView::showContextMenu );
107 connect( mDesigner->view(), &QgsLayoutView::itemFocused, this, &QgsLayoutItemsListView::onItemFocused );
108}
109
111{
112 mLayout = layout;
113 mModel = new QgsLayoutItemsListViewModel( layout->itemsModel(), this );
114 setModel( mModel );
115
116 header()->setSectionResizeMode( 0, QHeaderView::Fixed );
117 header()->setSectionResizeMode( 1, QHeaderView::Fixed );
118 setColumnWidth( 0, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'x' ) * 4 );
119 setColumnWidth( 1, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'x' ) * 4 );
120 header()->setSectionsMovable( false );
121
122 connect( selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsLayoutItemsListView::updateSelection );
123}
124
126{
127 if ( event->key() == Qt::Key_Space )
128 {
129 const auto constSelectedIndexes = selectionModel()->selectedIndexes();
130 if ( !constSelectedIndexes.isEmpty() )
131 {
132 const bool isFirstItemVisible = mModel->itemFromIndex( constSelectedIndexes[0] )->isVisible();
133
134 for ( const QModelIndex &index : constSelectedIndexes )
135 {
136 if ( QgsLayoutItem *item = mModel->itemFromIndex( index ) )
137 {
138 item->setVisibility( !isFirstItemVisible );
139 }
140 }
141 //return here, because otherwise it will just invert visibility for each item instead setting all the same
142 return;
143 }
144 }
145
146 QTreeView::keyPressEvent( event );
147}
148
149void QgsLayoutItemsListView::updateSelection()
150{
151 // Do nothing if we are currently updating the selection
152 // because user has selected/deselected some items in the
153 // graphics view
154 if ( !mModel || mUpdatingFromView )
155 return;
156
157 // Set the updating flag
158 mUpdatingSelection = true;
159
160 // Deselect all items from the layout (prevent firing signals, selection will be changed)
161 whileBlocking( mLayout )->deselectAll();
162
163 // Build the list of selected items
164 QList<QgsLayoutItem *> selectedItems;
165 for ( const QModelIndex &index : selectionModel()->selectedIndexes() )
166 {
167 if ( QgsLayoutItem *item = mModel->itemFromIndex( index ) )
168 {
169 selectedItems << item;
170 }
171 }
172
173
174 bool itemSelected = false;
175
176 // Check if the clicked item was selected or deselected
177 if ( selectionModel()->isSelected( selectionModel()->currentIndex() ) )
178 {
179 // It it was selected, set it as the layout's selected item;
180 // This will show the item properties
181 QgsLayoutItem *currentItem = mModel->itemFromIndex( selectionModel()->currentIndex() );
182 mLayout->setSelectedItem( currentItem );
183 itemSelected = true;
184 }
185 for ( QgsLayoutItem *item : selectedItems )
186 {
187 if ( !itemSelected )
188 {
189 // If clicked item was actually deselected, set the first selected item in the list
190 // as the layout's selected item
191 mLayout->setSelectedItem( item );
192 itemSelected = true;
193 }
194 else
195 {
196 item->setSelected( true );
197 }
198
199 // find top level group this item is contained within, and mark the group as selected
200 QgsLayoutItemGroup *group = item->parentGroup();
201 while ( group && group->parentGroup() )
202 {
203 group = group->parentGroup();
204 }
205 if ( group && group != item )
206 group->setSelected( true );
207 }
208 // Reset the updating flag
209 mUpdatingSelection = false;
210}
211
212void QgsLayoutItemsListView::onItemFocused( QgsLayoutItem *focusedItem )
213{
214 // Do nothing if we are in the middle of selecting items in the layoutView
215 if ( !mModel || mUpdatingSelection )
216 return;
217
218 // Set the updating flag
219 mUpdatingFromView = true;
220
221 // Deselect all items in list
222 clearSelection();
223
224 // Set the current index to the focused item
225 QModelIndex index = mModel->indexForItem( focusedItem );
226 if ( index.isValid() )
227 {
228 setCurrentIndex( index );
229 }
230
231 // Select rows in the item list for every selected items in the graphics view
232 const QList<QgsLayoutItem *> selectedItems = mLayout->selectedLayoutItems();
233 for ( QgsLayoutItem *item : selectedItems )
234 {
235 const QModelIndex firstCol = mModel->indexForItem( item );
236 if ( firstCol.isValid() )
237 {
238 // Select the whole row
239 QItemSelection selection;
240 selection.select( firstCol, firstCol.siblingAtColumn( mModel->columnCount( firstCol.parent() ) - 1 ) );
241 selectionModel()->select( selection, QItemSelectionModel::Select );
242 }
243 }
244 // Reset the updating flag
245 mUpdatingFromView = false;
246}
247
248void QgsLayoutItemsListView::showContextMenu( QPoint point )
249{
250 if ( !mModel )
251 return;
252 const QModelIndex index = indexAt( point );
253 QgsLayoutItem *item = mModel->itemFromIndex( index );
254 if ( !item )
255 return;
256
257 QMenu *menu = new QMenu( this );
258
259 QAction *copyAction = new QAction( tr( "Copy Item" ), menu );
260 connect( copyAction, &QAction::triggered, this, [this, item]() {
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 mDesigner->view()->deleteItems( QList<QgsLayoutItem *>() << item );
267 } );
268 menu->addAction( deleteAction );
269 menu->addSeparator();
270
271 QAction *itemPropertiesAction = new QAction( tr( "Item Properties…" ), menu );
272 connect( itemPropertiesAction, &QAction::triggered, this, [this, item]() {
273 mDesigner->showItemOptions( item, true );
274 } );
275 menu->addAction( itemPropertiesAction );
276
277 menu->popup( mapToGlobal( point ) );
278}
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:6222
A common interface for layout designer dialogs and widgets.
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.
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.
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:50
QgsLayoutModel * itemsModel()
Returns the items model attached to the layout.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:6511