QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
qgsprojectstoredobjectmanagermodel.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsprojectstoredobjectmanagermodel.cpp
3 --------------------
4 Date : January 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 <QIcon>
19#include <QMessageBox>
20
21#include "moc_qgsprojectstoredobjectmanagermodel.cpp"
22
23//
24// QgsProjectStoredObjectManagerModelBase
25//
26
28 : QAbstractListModel( parent )
29{
30
31}
32
33int QgsProjectStoredObjectManagerModelBase::rowCount( const QModelIndex &parent ) const
34{
35 return rowCountInternal( parent );
36}
37
38QVariant QgsProjectStoredObjectManagerModelBase::data( const QModelIndex &index, int role ) const
39{
40 return dataInternal( index, role );
41}
42
43bool QgsProjectStoredObjectManagerModelBase::setData( const QModelIndex &index, const QVariant &value, int role )
44{
45 return setDataInternal( index, value, role );
46}
47
48Qt::ItemFlags QgsProjectStoredObjectManagerModelBase::flags( const QModelIndex &index ) const
49{
50 return flagsInternal( index );
51}
52
54void QgsProjectStoredObjectManagerModelBase::objectAboutToBeAdded( const QString &name )
55{
56 objectAboutToBeAddedInternal( name );
57}
58
59void QgsProjectStoredObjectManagerModelBase::objectAboutToBeRemoved( const QString &name )
60{
61 objectAboutToBeRemovedInternal( name );
62}
63
64void QgsProjectStoredObjectManagerModelBase::objectAdded( const QString &name )
65{
66 objectAddedInternal( name );
67}
68
69void QgsProjectStoredObjectManagerModelBase::objectRemoved( const QString &name )
70{
71 objectRemovedInternal( name );
72}
74
75//
76// QgsProjectStoredObjectManagerModel
77//
78template<class T>
81 , mObjectManager( manager )
82{
83 connect( mObjectManager, &QgsProjectStoredObjectManagerBase::objectAboutToBeAdded, this, &QgsProjectStoredObjectManagerModel::objectAboutToBeAdded );
84 connect( mObjectManager, &QgsProjectStoredObjectManagerBase::objectAdded, this, &QgsProjectStoredObjectManagerModel::objectAdded );
85 connect( mObjectManager, &QgsProjectStoredObjectManagerBase::objectAboutToBeRemoved, this, &QgsProjectStoredObjectManagerModel::objectAboutToBeRemoved );
86 connect( mObjectManager, &QgsProjectStoredObjectManagerBase::objectRemoved, this, &QgsProjectStoredObjectManagerModel::objectRemoved );
87}
88
90template<class T>
91int QgsProjectStoredObjectManagerModel<T>::rowCountInternal( const QModelIndex &parent ) const
92{
93 Q_UNUSED( parent )
94 return ( mObjectManager ? mObjectManager->objects().count() : 0 ) + ( mAllowEmpty ? 1 : 0 );
95}
96
97template<class T>
98QVariant QgsProjectStoredObjectManagerModel<T>::dataInternal( const QModelIndex &index, int role ) const
99{
100 if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) )
101 return QVariant();
102
103 const bool isEmpty = index.row() == 0 && mAllowEmpty;
104 const int objectRow = mAllowEmpty ? index.row() - 1 : index.row();
105
106 switch ( role )
107 {
108 case Qt::DisplayRole:
109 case Qt::ToolTipRole:
110 case Qt::EditRole:
111 return !isEmpty && mObjectManager ? mObjectManager->objects().at( objectRow )->name() : QVariant();
112
113 case static_cast< int >( CustomRole::Object ):
114 {
115 if ( isEmpty || !mObjectManager )
116 return QVariant();
117 return objectToVariant( mObjectManager->objects().at( objectRow ) );
118 }
119
120 case Qt::DecorationRole:
121 {
122 return isEmpty || !mObjectManager ? QIcon() : mObjectManager->objects().at( objectRow )->icon();
123 }
124
125 default:
126 return QVariant();
127 }
129
130template<class T>
131bool QgsProjectStoredObjectManagerModel<T>::setDataInternal( const QModelIndex &index, const QVariant &value, int role )
132{
133 if ( !index.isValid() || role != Qt::EditRole )
134 {
135 return false;
136 }
137 if ( index.row() >= mObjectManager->objects().count() )
138 {
139 return false;
140 }
141
142 if ( index.row() == 0 && mAllowEmpty )
143 return false;
144
145 if ( value.toString().isEmpty() )
146 return false;
147
148 T *object = objectFromIndex( index );
149 if ( !object )
150 return false;
151
152 //has name changed?
153 bool changed = object->name() != value.toString();
154 if ( !changed )
155 return true;
156
157 //check if name already exists
158 QStringList existingNames;
159 const QList< T * > objects = mObjectManager->objects();
160 for ( T *l : objects )
161 {
162 existingNames << l->name();
163 }
164 if ( existingNames.contains( value.toString() ) )
165 {
166 //name exists!
167 QMessageBox::warning( nullptr, tr( "Rename Layout" ), tr( "There is already a layout named “%1”." ).arg( value.toString() ) );
168 return false;
169 }
170
171 object->setName( value.toString() );
172 return true;
173}
174
175template<class T>
176Qt::ItemFlags QgsProjectStoredObjectManagerModel<T>::flagsInternal( const QModelIndex &index ) const
177{
178 Qt::ItemFlags flags = QAbstractListModel::flags( index );
179#if 0 // double-click is now used for opening the object
180 if ( index.isValid() )
181 {
182 return flags | Qt::ItemIsEditable;
183 }
184 else
185 {
186 return flags;
187 }
188#endif
189 return flags;
190}
191
192template<class T>
194{
195 int row = mObjectManager->objects().count() + ( mAllowEmpty ? 1 : 0 );
196 beginInsertRows( QModelIndex(), row, row );
197}
198
199template<class T>
201{
202 T *l = mObjectManager->objectByName( name );
203 int row = mObjectManager->objects().indexOf( l ) + ( mAllowEmpty ? 1 : 0 );
204 if ( row >= 0 )
205 beginRemoveRows( QModelIndex(), row, row );
206}
207
208template<class T>
210{
211 endInsertRows();
212}
213
214template<class T>
216{
217 endRemoveRows();
218}
219
220template<class T>
222{
223 int row = mObjectManager->objects().indexOf( object ) + ( mAllowEmpty ? 1 : 0 );
224 QModelIndex index = createIndex( row, 0 );
225 emit dataChanged( index, index, QVector<int>() << Qt::DisplayRole );
226}
227
228template<class T>
230{
231 if ( T *l = dynamic_cast< T * >( object ) )
232 return QVariant::fromValue( l );
233 return QVariant();
234}
235
236
237///@endcond
238
239template<class T>
242 if ( index.row() == 0 && mAllowEmpty )
243 return nullptr;
244
245 if ( T *l = qobject_cast< T * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Object ) ) ) ) )
246 return l;
247 else
248 return nullptr;
249}
250
251template<class T>
253{
254 if ( !mObjectManager )
255 {
256 return QModelIndex();
257 }
258
259 const int r = mObjectManager->objects().indexOf( object );
260 if ( r < 0 )
261 return QModelIndex();
262
263 QModelIndex idx = index( mAllowEmpty ? r + 1 : r, 0, QModelIndex() );
264 if ( idx.isValid() )
265 {
266 return idx;
267 }
268
269 return QModelIndex();
270}
271
272template<class T>
274{
275 if ( allowEmpty == mAllowEmpty )
276 return;
277
278 if ( allowEmpty )
279 {
280 beginInsertRows( QModelIndex(), 0, 0 );
281 mAllowEmpty = true;
282 endInsertRows();
283 }
284 else
285 {
286 beginRemoveRows( QModelIndex(), 0, 0 );
287 mAllowEmpty = false;
288 endRemoveRows();
289 }
290}
291
292
294#include "qgsprintlayout.h"
295#include "qgsreport.h"
296
298template<>
300{
301 if ( QgsLayout *l = dynamic_cast< QgsLayout * >( object ) )
302 return QVariant::fromValue( l );
303 else if ( QgsReport *r = dynamic_cast< QgsReport * >( object ) )
304 return QVariant::fromValue( r );
305 return QVariant();
306}
307
308template<>
310{
311 if ( index.row() == 0 && mAllowEmpty )
312 return nullptr;
313
314 if ( QgsPrintLayout *l = qobject_cast< QgsPrintLayout * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Object ) ) ) ) )
315 return l;
316 else if ( QgsReport *r = qobject_cast< QgsReport * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Object ) ) ) ) )
317 return r;
318 else
319 return nullptr;
320}
321
322template class QgsProjectStoredObjectManagerModel<QgsMasterLayoutInterface>; // clazy:exclude=missing-qobject-macro
323
324
325#include "qgselevationprofile.h"
326template class QgsProjectStoredObjectManagerModel<QgsElevationProfile>; // clazy:exclude=missing-qobject-macro
327
329
330//
331// QgsProjectStoredObjectManagerProxyModelBase
332//
333
335 : QSortFilterProxyModel( parent )
336{
337 setDynamicSortFilter( true );
338 sort( 0 );
339 setSortCaseSensitivity( Qt::CaseInsensitive );
340}
341
342bool QgsProjectStoredObjectManagerProxyModelBase::lessThan( const QModelIndex &left, const QModelIndex &right ) const
343{
344 const QString leftText = sourceModel()->data( left, Qt::DisplayRole ).toString();
345 const QString rightText = sourceModel()->data( right, Qt::DisplayRole ).toString();
346 if ( leftText.isEmpty() )
347 return true;
348 if ( rightText.isEmpty() )
349 return false;
350
351 return QString::localeAwareCompare( leftText, rightText ) < 0;
352}
353
354bool QgsProjectStoredObjectManagerProxyModelBase::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
355{
356 return filterAcceptsRowInternal( sourceRow, sourceParent );
357}
358
360{
361 mFilterString = filter;
362 invalidateFilter();
363}
364
366{
367 return true;
368}
369
370//
371// QgsProjectStoredObjectManagerProxyModel
372//
373
374template<class T>
380
381template<class T>
382bool QgsProjectStoredObjectManagerProxyModel<T>::filterAcceptsRowInternal( int sourceRow, const QModelIndex &sourceParent ) const
383{
384 QgsProjectStoredObjectManagerModel<T> *model = dynamic_cast< QgsProjectStoredObjectManagerModel<T> * >( sourceModel() );
385 if ( !model )
386 return false;
387
388 T *object = model->objectFromIndex( model->index( sourceRow, 0, sourceParent ) );
389 if ( !object )
390 return model->allowEmptyObject();
391
392 if ( !mFilterString.trimmed().isEmpty() )
393 {
394 if ( !object->name().contains( mFilterString, Qt::CaseInsensitive ) )
395 return false;
396 }
397
398 return true;
399}
400
402template class QgsProjectStoredObjectManagerProxyModel<QgsMasterLayoutInterface>; // clazy:exclude=missing-qobject-macro
403template class QgsProjectStoredObjectManagerProxyModel<QgsElevationProfile>; // clazy:exclude=missing-qobject-macro
Template class for storage of a set of objects attached to a QgsProject.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition qgslayout.h:50
Interface for master layout type objects, such as print layouts and reports.
Print layout, a QgsLayout subclass for static or atlas-based layouts.
void objectAdded(const QString &name)
Emitted when an object has been added to the manager.
void objectRemoved(const QString &name)
Emitted when an object was removed from the manager.
void objectAboutToBeAdded(const QString &name)
Emitted when an object is about to be added to the manager.
void objectAboutToBeRemoved(const QString &name)
Emitted when an object is about to be removed from the manager.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
Qt::ItemFlags flags(const QModelIndex &index) const override
QgsProjectStoredObjectManagerModelBase(QObject *parent=nullptr)
Constructor for QgsProjectStoredObjectManagerModelBase, with the specified parent object.
int rowCount(const QModelIndex &parent) const override
QVariant data(const QModelIndex &index, int role) const override
Template class for models representing the objects available in a QgsAbstractProjectStoredObjectManag...
void setAllowEmptyObject(bool allowEmpty)
Sets whether an optional empty object ("not set") option is present in the model.
QModelIndex indexFromObject(T *object) const
Returns the model index corresponding to an object.
T * objectFromIndex(const QModelIndex &index) const
Returns the object at the corresponding index.
QgsProjectStoredObjectManagerModel(QgsAbstractProjectStoredObjectManager< T > *manager, QObject *parent=nullptr)
Constructor for QgsProjectStoredObjectManagerModel, showing the objects from the specified manager.
PRIVATE QgsAbstractProjectStoredObjectManager< T > * mObjectManager
Object manager.
bool allowEmptyObject() const
Returns true if the model allows the empty object ("not set") choice.
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
void setFilterString(const QString &filter)
Sets a filter string, such that only layouts with names containing the specified string will be shown...
QgsProjectStoredObjectManagerProxyModelBase(QObject *parent=nullptr)
Constructor for QgsProjectStoredObjectManagerProxyModelBase.
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
virtual bool filterAcceptsRowInternal(int sourceRow, const QModelIndex &sourceParent) const
Returns true if the proxy accepts the matching source row.
Template class QSortFilterProxyModel subclass for QgsProjectStoredObjectManagerModel.
bool filterAcceptsRowInternal(int sourceRow, const QModelIndex &sourceParent) const override
Returns true if the proxy accepts the matching source row.
QgsProjectStoredObjectManagerProxyModel(QObject *parent=nullptr)
Constructor for QgsProjectStoredObjectManagerProxyModel.