QGIS API Documentation 3.99.0-Master (09f76ad7019)
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 static_cast< int >( CustomRole::IsEmptyObject ):
121 {
122 return isEmpty;
124
125 case Qt::DecorationRole:
126 {
127 if ( isEmpty || !mObjectManager )
128 return QIcon();
130 T *object = mObjectManager->objects().at( objectRow );
131 if constexpr( requires { object->icon(); } )
132 {
133 return object->icon();
134 }
135 else
136 {
137 return QIcon();
138 }
139 }
140
141 default:
142 return QVariant();
143 }
144}
145
146template<class T>
147bool QgsProjectStoredObjectManagerModel<T>::setDataInternal( const QModelIndex &index, const QVariant &value, int role )
148{
149 if ( !index.isValid() || role != Qt::EditRole )
150 {
151 return false;
152 }
153 if ( index.row() >= mObjectManager->objects().count() )
154 {
155 return false;
156 }
157
158 if ( index.row() == 0 && mAllowEmpty )
159 return false;
160
161 if ( value.toString().isEmpty() )
162 return false;
163
164 T *object = objectFromIndex( index );
165 if ( !object )
166 return false;
167
168 //has name changed?
169 bool changed = object->name() != value.toString();
170 if ( !changed )
171 return true;
172
173 //check if name already exists
174 QStringList existingNames;
175 const QList< T * > objects = mObjectManager->objects();
176 for ( T *l : objects )
177 {
178 existingNames << l->name();
179 }
180 if ( existingNames.contains( value.toString() ) )
181 {
182 //name exists!
183 QMessageBox::warning( nullptr, tr( "Rename Layout" ), tr( "There is already a layout named “%1”." ).arg( value.toString() ) );
184 return false;
185 }
186
187 object->setName( value.toString() );
188 return true;
189}
190
191template<class T>
192Qt::ItemFlags QgsProjectStoredObjectManagerModel<T>::flagsInternal( const QModelIndex &index ) const
193{
194 Qt::ItemFlags flags = QAbstractListModel::flags( index );
195#if 0 // double-click is now used for opening the object
196 if ( index.isValid() )
197 {
198 return flags | Qt::ItemIsEditable;
199 }
200 else
201 {
202 return flags;
203 }
204#endif
205 return flags;
206}
207
208template<class T>
210{
211 int row = mObjectManager->objects().count() + ( mAllowEmpty ? 1 : 0 );
212 beginInsertRows( QModelIndex(), row, row );
213}
214
215template<class T>
217{
218 T *l = mObjectManager->objectByName( name );
219 int row = mObjectManager->objects().indexOf( l ) + ( mAllowEmpty ? 1 : 0 );
220 if ( row >= 0 )
221 beginRemoveRows( QModelIndex(), row, row );
222}
223
224template<class T>
226{
227 endInsertRows();
228}
229
230template<class T>
232{
233 endRemoveRows();
234}
235
236template<class T>
239 int row = mObjectManager->objects().indexOf( object ) + ( mAllowEmpty ? 1 : 0 );
240 QModelIndex index = createIndex( row, 0 );
241 emit dataChanged( index, index, QVector<int>() << Qt::DisplayRole );
243
244template<class T>
246{
247 if ( T *l = dynamic_cast< T * >( object ) )
248 return QVariant::fromValue( l );
249 return QVariant();
250}
251
252
254
255template<class T>
257{
258 if ( index.row() == 0 && mAllowEmpty )
259 return nullptr;
260
261 if ( T *l = qobject_cast< T * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Object ) ) ) ) )
262 return l;
263 else
264 return nullptr;
265}
266
267template<class T>
269{
270 if ( !mObjectManager )
271 {
272 return QModelIndex();
273 }
274
275 const int r = mObjectManager->objects().indexOf( object );
276 if ( r < 0 )
277 return QModelIndex();
278
279 QModelIndex idx = index( mAllowEmpty ? r + 1 : r, 0, QModelIndex() );
280 if ( idx.isValid() )
281 {
282 return idx;
283 }
284
285 return QModelIndex();
286}
287
288template<class T>
290{
291 if ( allowEmpty == mAllowEmpty )
292 return;
293
294 if ( allowEmpty )
295 {
296 beginInsertRows( QModelIndex(), 0, 0 );
297 mAllowEmpty = true;
298 endInsertRows();
299 }
300 else
301 {
302 beginRemoveRows( QModelIndex(), 0, 0 );
303 mAllowEmpty = false;
304 endRemoveRows();
305 }
306}
307
308
310#include "qgsprintlayout.h"
311#include "qgsreport.h"
312
314template<>
316{
317 if ( QgsLayout *l = dynamic_cast< QgsLayout * >( object ) )
318 return QVariant::fromValue( l );
319 else if ( QgsReport *r = dynamic_cast< QgsReport * >( object ) )
320 return QVariant::fromValue( r );
321 return QVariant();
322}
323
324template<>
326{
327 if ( index.row() == 0 && mAllowEmpty )
328 return nullptr;
329
330 if ( QgsPrintLayout *l = qobject_cast< QgsPrintLayout * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Object ) ) ) ) )
331 return l;
332 else if ( QgsReport *r = qobject_cast< QgsReport * >( qvariant_cast<QObject *>( data( index, static_cast< int >( CustomRole::Object ) ) ) ) )
333 return r;
334 else
335 return nullptr;
336}
337
338template class QgsProjectStoredObjectManagerModel<QgsMasterLayoutInterface>; // clazy:exclude=missing-qobject-macro
339
340
341#include "qgselevationprofile.h"
342template class QgsProjectStoredObjectManagerModel<QgsElevationProfile>; // clazy:exclude=missing-qobject-macro
343
345
346template<>
348{
349 if ( object )
350 return QVariant::fromValue( object );
351 return QVariant();
352}
353
354template<>
356{
357 if ( index.row() == 0 && mAllowEmpty )
358 return nullptr;
359
360 const QVariant variant = data( index, static_cast< int >( CustomRole::Object ) );
361 return qvariant_cast< QgsSelectiveMaskingSourceSet *>( variant );
362}
363
364template<>
366{
367 if ( !mObjectManager )
368 {
369 return QModelIndex();
370 }
371
372 const QList< QgsSelectiveMaskingSourceSet * > objects = mObjectManager->objects();
373 int r = 0;
374 bool foundMatch = false;
375 for ( QgsSelectiveMaskingSourceSet *set : objects )
376 {
377 if ( set && set->id() == object->id() )
378 {
379 foundMatch = true;
380 break;
381 }
382 r++;
383 }
384 if ( !foundMatch )
385 return QModelIndex();
386
387 QModelIndex idx = index( mAllowEmpty ? r + 1 : r, 0, QModelIndex() );
388 if ( idx.isValid() )
389 {
390 return idx;
391 }
392
393 return QModelIndex();
394}
395
396
397template class QgsProjectStoredObjectManagerModel<QgsSelectiveMaskingSourceSet>; // clazy:exclude=missing-qobject-macro
398
400
401//
402// QgsProjectStoredObjectManagerProxyModelBase
403//
404
406 : QSortFilterProxyModel( parent )
407{
408 setDynamicSortFilter( true );
409 sort( 0 );
410 setSortCaseSensitivity( Qt::CaseInsensitive );
411}
412
413bool QgsProjectStoredObjectManagerProxyModelBase::lessThan( const QModelIndex &left, const QModelIndex &right ) const
414{
415 if ( qobject_cast< QgsProjectStoredObjectManagerModelBase * >( sourceModel() ) )
416 {
417 const bool leftIsEmpty = sourceModel()->data( left, static_cast< int >( QgsProjectStoredObjectManagerModelBase::CustomRole::IsEmptyObject ) ).toBool();
418 const bool rightIsEmpty = sourceModel()->data( right, static_cast< int >( QgsProjectStoredObjectManagerModelBase::CustomRole::IsEmptyObject ) ).toBool();
419 if ( leftIsEmpty )
420 return true;
421 if ( rightIsEmpty )
422 return false;
423 }
424
425 const QString leftText = sourceModel()->data( left, Qt::DisplayRole ).toString();
426 const QString rightText = sourceModel()->data( right, Qt::DisplayRole ).toString();
427 if ( leftText.isEmpty() )
428 return true;
429 if ( rightText.isEmpty() )
430 return false;
431
432 return QString::localeAwareCompare( leftText, rightText ) < 0;
433}
434
435bool QgsProjectStoredObjectManagerProxyModelBase::filterAcceptsRow( int sourceRow, const QModelIndex &sourceParent ) const
436{
437 return filterAcceptsRowInternal( sourceRow, sourceParent );
438}
439
441{
442 mFilterString = filter;
443 invalidateFilter();
444}
445
447{
448 return true;
449}
450
451//
452// QgsProjectStoredObjectManagerProxyModel
453//
454
455template<class T>
461
462template<class T>
463bool QgsProjectStoredObjectManagerProxyModel<T>::filterAcceptsRowInternal( int sourceRow, const QModelIndex &sourceParent ) const
464{
465 QgsProjectStoredObjectManagerModel<T> *model = dynamic_cast< QgsProjectStoredObjectManagerModel<T> * >( sourceModel() );
466 if ( !model )
467 return false;
468
469 T *object = model->objectFromIndex( model->index( sourceRow, 0, sourceParent ) );
470 if ( !object )
471 return model->allowEmptyObject();
472
473 if ( !mFilterString.trimmed().isEmpty() )
474 {
475 if ( !object->name().contains( mFilterString, Qt::CaseInsensitive ) )
476 return false;
477 }
478
479 return true;
480}
481
483template class QgsProjectStoredObjectManagerProxyModel<QgsMasterLayoutInterface>; // clazy:exclude=missing-qobject-macro
484template class QgsProjectStoredObjectManagerProxyModel<QgsElevationProfile>; // clazy:exclude=missing-qobject-macro
485template 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.