QGIS API Documentation 4.0.0-Norrköping (1ddcee3d0e4)
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
31int QgsProjectStoredObjectManagerModelBase::rowCount( const QModelIndex &parent ) const
32{
33 return rowCountInternal( parent );
34}
35
36QVariant QgsProjectStoredObjectManagerModelBase::data( const QModelIndex &index, int role ) const
37{
38 return dataInternal( index, role );
39}
40
41bool QgsProjectStoredObjectManagerModelBase::setData( const QModelIndex &index, const QVariant &value, int role )
42{
43 return setDataInternal( index, value, role );
44}
45
46Qt::ItemFlags QgsProjectStoredObjectManagerModelBase::flags( const QModelIndex &index ) const
47{
48 return flagsInternal( index );
49}
50
52void QgsProjectStoredObjectManagerModelBase::objectAboutToBeAdded( const QString &name )
53{
54 objectAboutToBeAddedInternal( name );
55}
56
57void QgsProjectStoredObjectManagerModelBase::objectAboutToBeRemoved( const QString &name )
58{
59 objectAboutToBeRemovedInternal( name );
60}
61
62void QgsProjectStoredObjectManagerModelBase::objectAdded( const QString &name )
63{
64 objectAddedInternal( name );
65}
66
67void QgsProjectStoredObjectManagerModelBase::objectRemoved( const QString &name )
68{
69 objectRemovedInternal( name );
70}
72
73//
74// QgsProjectStoredObjectManagerModel
75//
78 , mObjectManager( manager )
79{
80 connect( mObjectManager, &QgsProjectStoredObjectManagerBase::objectAboutToBeAdded, this, &QgsProjectStoredObjectManagerModel::objectAboutToBeAdded );
81 connect( mObjectManager, &QgsProjectStoredObjectManagerBase::objectAdded, this, &QgsProjectStoredObjectManagerModel::objectAdded );
82 connect( mObjectManager, &QgsProjectStoredObjectManagerBase::objectAboutToBeRemoved, this, &QgsProjectStoredObjectManagerModel::objectAboutToBeRemoved );
83 connect( mObjectManager, &QgsProjectStoredObjectManagerBase::objectRemoved, this, &QgsProjectStoredObjectManagerModel::objectRemoved );
84}
85
87template<class T> int QgsProjectStoredObjectManagerModel<T>::rowCountInternal( const QModelIndex &parent ) const
88{
89 Q_UNUSED( parent )
90 return ( mObjectManager ? mObjectManager->objects().count() : 0 ) + ( mAllowEmpty ? 1 : 0 );
91}
92
93template<class T> QVariant QgsProjectStoredObjectManagerModel<T>::dataInternal( const QModelIndex &index, int role ) const
94{
95 if ( index.row() < 0 || index.row() >= rowCount( QModelIndex() ) )
96 return QVariant();
97
98 const bool isEmpty = index.row() == 0 && mAllowEmpty;
99 const int objectRow = mAllowEmpty ? index.row() - 1 : index.row();
100
101 switch ( role )
102 {
103 case Qt::DisplayRole:
104 case Qt::ToolTipRole:
105 case Qt::EditRole:
106 return !isEmpty && mObjectManager ? mObjectManager->objects().at( objectRow )->name() : QVariant();
107
108 case static_cast< int >( CustomRole::Object ):
109 {
110 if ( isEmpty || !mObjectManager )
111 return QVariant();
112 return objectToVariant( mObjectManager->objects().at( objectRow ) );
113 }
114
115 case static_cast< int >( CustomRole::IsEmptyObject ):
116 {
117 return isEmpty;
119
120 case Qt::DecorationRole:
121 {
122 if ( isEmpty || !mObjectManager )
123 return QIcon();
125 T *object = mObjectManager->objects().at( objectRow );
126 if constexpr ( requires { object->icon(); } )
127 {
128 return object->icon();
129 }
130 else
131 {
132 return QIcon();
133 }
134 }
135
136 default:
137 return QVariant();
138 }
139}
140
141template<class T> bool QgsProjectStoredObjectManagerModel<T>::setDataInternal( const QModelIndex &index, const QVariant &value, int role )
142{
143 if ( !index.isValid() || role != Qt::EditRole )
144 {
145 return false;
146 }
147 if ( index.row() >= mObjectManager->objects().count() )
148 {
149 return false;
150 }
151
152 if ( index.row() == 0 && mAllowEmpty )
153 return false;
154
155 if ( value.toString().isEmpty() )
156 return false;
157
158 T *object = objectFromIndex( index );
159 if ( !object )
160 return false;
161
162 //has name changed?
163 bool changed = object->name() != value.toString();
164 if ( !changed )
165 return true;
166
167 //check if name already exists
168 QStringList existingNames;
169 const QList< T * > objects = mObjectManager->objects();
170 for ( T *l : objects )
171 {
172 existingNames << l->name();
173 }
174 if ( existingNames.contains( value.toString() ) )
175 {
176 //name exists!
177 QMessageBox::warning( nullptr, tr( "Rename Layout" ), tr( "There is already a layout named “%1”." ).arg( value.toString() ) );
178 return false;
179 }
180
181 object->setName( value.toString() );
182 return true;
183}
184
185template<class T> Qt::ItemFlags QgsProjectStoredObjectManagerModel<T>::flagsInternal( const QModelIndex &index ) const
186{
187 Qt::ItemFlags flags = QAbstractListModel::flags( index );
188#if 0 // double-click is now used for opening the object
189 if ( index.isValid() )
190 {
191 return flags | Qt::ItemIsEditable;
192 }
193 else
194 {
195 return flags;
196 }
197#endif
198 return flags;
199}
200
201template<class T> void QgsProjectStoredObjectManagerModel<T>::objectAboutToBeAddedInternal( const QString & )
202{
203 int row = mObjectManager->objects().count() + ( mAllowEmpty ? 1 : 0 );
204 beginInsertRows( QModelIndex(), row, row );
205}
206
207template<class T> void QgsProjectStoredObjectManagerModel<T>::objectAboutToBeRemovedInternal( const QString &name )
208{
209 T *l = mObjectManager->objectByName( name );
210 int row = mObjectManager->objects().indexOf( l ) + ( mAllowEmpty ? 1 : 0 );
211 if ( row >= 0 )
212 beginRemoveRows( QModelIndex(), row, row );
213}
214
215template<class T> void QgsProjectStoredObjectManagerModel<T>::objectAddedInternal( const QString & )
216{
217 endInsertRows();
218}
219
220template<class T> void QgsProjectStoredObjectManagerModel<T>::objectRemovedInternal( const QString & )
221{
222 endRemoveRows();
223}
224
225template<class T> void QgsProjectStoredObjectManagerModel<T>::objectRenamedInternal( T *object, const QString & )
226{
227 int row = mObjectManager->objects().indexOf( object ) + ( mAllowEmpty ? 1 : 0 );
228 QModelIndex index = createIndex( row, 0 );
229 emit dataChanged( index, index, QVector<int>() << Qt::DisplayRole );
230}
231
232template<class T> QVariant QgsProjectStoredObjectManagerModel<T>::objectToVariant( T *object ) const
233{
234 if ( T *l = dynamic_cast< T * >( object ) )
235 return QVariant::fromValue( l );
236 return QVariant();
237}
238
239
241
242template<class T> T *QgsProjectStoredObjectManagerModel<T>::objectFromIndex( const QModelIndex &index ) const
243{
244 if ( index.row() == 0 && mAllowEmpty )
245 return nullptr;
246
247 if ( T *l = qobject_cast< T * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Object ) ) ) ) )
248 return l;
249 else
250 return nullptr;
251}
252
253template<class T> QModelIndex QgsProjectStoredObjectManagerModel<T>::indexFromObject( T *object ) const
254{
255 if ( !mObjectManager )
256 {
257 return QModelIndex();
258 }
259
260 const int r = mObjectManager->objects().indexOf( object );
261 if ( r < 0 )
262 return QModelIndex();
263
264 QModelIndex idx = index( mAllowEmpty ? r + 1 : r, 0, QModelIndex() );
265 if ( idx.isValid() )
266 {
267 return idx;
268 }
269
270 return QModelIndex();
271}
272
273template<class T> void QgsProjectStoredObjectManagerModel<T>::setAllowEmptyObject( bool allowEmpty )
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
299{
300 if ( QgsLayout *l = dynamic_cast< QgsLayout * >( object ) )
301 return QVariant::fromValue( l );
302 else if ( QgsReport *r = dynamic_cast< QgsReport * >( object ) )
303 return QVariant::fromValue( r );
304 return QVariant();
305}
306
308{
309 if ( index.row() == 0 && mAllowEmpty )
310 return nullptr;
311
312 if ( QgsPrintLayout *l = qobject_cast< QgsPrintLayout * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Object ) ) ) ) )
313 return l;
314 else if ( QgsReport *r = qobject_cast< QgsReport * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Object ) ) ) ) )
315 return r;
316 else
317 return nullptr;
318}
319
320template class QgsProjectStoredObjectManagerModel<QgsMasterLayoutInterface>; // clazy:exclude=missing-qobject-macro
321
322
323#include "qgselevationprofile.h"
324template class QgsProjectStoredObjectManagerModel<QgsElevationProfile>; // clazy:exclude=missing-qobject-macro
325
327
329{
330 if ( object )
331 return QVariant::fromValue( object );
332 return QVariant();
333}
334
336{
337 if ( index.row() == 0 && mAllowEmpty )
338 return nullptr;
339
340 const QVariant variant = data( index, static_cast< int >( CustomRole::Object ) );
341 return qvariant_cast< QgsSelectiveMaskingSourceSet *>( variant );
342}
343
345{
346 if ( !mObjectManager )
347 {
348 return QModelIndex();
349 }
350
351 const QList< QgsSelectiveMaskingSourceSet * > objects = mObjectManager->objects();
352 int r = 0;
353 bool foundMatch = false;
354 for ( QgsSelectiveMaskingSourceSet *set : objects )
355 {
356 if ( set && set->id() == object->id() )
357 {
358 foundMatch = true;
359 break;
360 }
361 r++;
362 }
363 if ( !foundMatch )
364 return QModelIndex();
365
366 QModelIndex idx = index( mAllowEmpty ? r + 1 : r, 0, QModelIndex() );
367 if ( idx.isValid() )
368 {
369 return idx;
370 }
371
372 return QModelIndex();
373}
374
375
376template class QgsProjectStoredObjectManagerModel<QgsSelectiveMaskingSourceSet>; // clazy:exclude=missing-qobject-macro
377
379
380//
381// QgsProjectStoredObjectManagerProxyModelBase
382//
383
385 : QSortFilterProxyModel( parent )
386{
387 setDynamicSortFilter( true );
388 sort( 0 );
389 setSortCaseSensitivity( Qt::CaseInsensitive );
390}
391
392bool QgsProjectStoredObjectManagerProxyModelBase::lessThan( const QModelIndex &left, const QModelIndex &right ) const
393{
394 if ( qobject_cast< QgsProjectStoredObjectManagerModelBase * >( sourceModel() ) )
395 {
396 const bool leftIsEmpty = sourceModel()->data( left, static_cast< int >( QgsProjectStoredObjectManagerModelBase::CustomRole::IsEmptyObject ) ).toBool();
397 const bool rightIsEmpty = sourceModel()->data( right, static_cast< int >( QgsProjectStoredObjectManagerModelBase::CustomRole::IsEmptyObject ) ).toBool();
398 if ( leftIsEmpty )
399 return true;
400 if ( rightIsEmpty )
401 return false;
402 }
403
404 const QString leftText = sourceModel()->data( left, Qt::DisplayRole ).toString();
405 const QString rightText = sourceModel()->data( right, Qt::DisplayRole ).toString();
406 if ( leftText.isEmpty() )
407 return true;
408 if ( rightText.isEmpty() )
409 return false;
410
411 return QString::localeAwareCompare( leftText, rightText ) < 0;
412}
413
414bool QgsProjectStoredObjectManagerProxyModelBase::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
415{
416 return filterAcceptsRowInternal( sourceRow, sourceParent );
417}
418
420{
421 mFilterString = filter;
422 invalidateFilter();
423}
424
426{
427 return true;
428}
429
430//
431// QgsProjectStoredObjectManagerProxyModel
432//
433
437
438template<class T> bool QgsProjectStoredObjectManagerProxyModel<T>::filterAcceptsRowInternal( int sourceRow, const QModelIndex &sourceParent ) const
439{
440 QgsProjectStoredObjectManagerModel<T> *model = dynamic_cast< QgsProjectStoredObjectManagerModel<T> * >( sourceModel() );
441 if ( !model )
442 return false;
443
444 T *object = model->objectFromIndex( model->index( sourceRow, 0, sourceParent ) );
445 if ( !object )
446 return model->allowEmptyObject();
447
448 if ( !mFilterString.trimmed().isEmpty() )
449 {
450 if ( !object->name().contains( mFilterString, Qt::CaseInsensitive ) )
451 return false;
452 }
453
454 return true;
455}
456
458template class QgsProjectStoredObjectManagerProxyModel<QgsMasterLayoutInterface>; // clazy:exclude=missing-qobject-macro
459template class QgsProjectStoredObjectManagerProxyModel<QgsElevationProfile>; // clazy:exclude=missing-qobject-macro
460template class QgsProjectStoredObjectManagerProxyModel<QgsSelectiveMaskingSourceSet>; // 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.
Represents a named set of selective masking sources (QgsSelectiveMaskSource).
QString id() const
Returns a unique identifier for the set.