43 if ( !layout || mLayouts.contains( layout ) )
49 if ( l->name() == layout->
name() )
64 else if ( QgsReport *r =
dynamic_cast< QgsReport *
>( layout ) )
66 connect( r, &QgsReport::nameChanged,
this, [
this, r](
const QString & newName )
84 if ( !mLayouts.contains( layout ) )
87 QString name = layout->
name();
89 mLayouts.removeAll( layout );
98 const QList< QgsMasterLayoutInterface * >
layouts = mLayouts;
112 QList<QgsPrintLayout *> result;
113 const QList<QgsMasterLayoutInterface *> _layouts( mLayouts );
114 result.reserve( _layouts.size() );
115 for (
const auto &layout : _layouts )
119 result.push_back( _item );
128 if ( l->name() == name )
138 QDomElement layoutsElem = element;
139 if ( element.tagName() != QLatin1String(
"Layouts" ) )
141 layoutsElem = element.firstChildElement( QStringLiteral(
"Layouts" ) );
143 if ( layoutsElem.isNull() )
146 layoutsElem = doc.documentElement();
151 QDomNodeList composerNodes = element.elementsByTagName( QStringLiteral(
"Composer" ) );
153 for (
int i = 0; i < composerNodes.size(); ++i )
156 QString legacyTitle = composerNodes.at( i ).toElement().attribute( QStringLiteral(
"title" ) );
158 QDomNodeList compositionNodes = composerNodes.at( i ).toElement().elementsByTagName( QStringLiteral(
"Composition" ) );
159 for (
int j = 0; j < compositionNodes.size(); ++j )
164 if ( l->name().isEmpty() )
165 l->setName( legacyTitle );
170 bool isDuplicateName =
false;
171 QString originalName = l->name();
174 isDuplicateName =
false;
177 if ( l->name() == layout->name() )
179 isDuplicateName =
true;
183 if ( isDuplicateName )
185 l->setName( QStringLiteral(
"%1 %2" ).arg( originalName ).arg(
id ) );
189 while ( isDuplicateName );
192 result = added && result;
200 profile.
switchTask( tr(
"Creating layouts" ) );
203 const QDomNodeList layoutNodes = layoutsElem.childNodes();
204 for (
int i = 0; i < layoutNodes.size(); ++i )
206 if ( layoutNodes.at( i ).nodeName() != QLatin1String(
"Layout" ) )
209 const QString layoutName = layoutNodes.at( i ).toElement().attribute( QStringLiteral(
"name" ) );
212 std::unique_ptr< QgsPrintLayout > l = std::make_unique< QgsPrintLayout >( mProject );
213 l->undoStack()->blockCommands(
true );
214 if ( !l->readLayoutXml( layoutNodes.at( i ).toElement(), doc, context ) )
219 l->undoStack()->blockCommands(
false );
226 profile.
switchTask( tr(
"Creating reports" ) );
227 const QDomNodeList reportNodes = element.elementsByTagName( QStringLiteral(
"Report" ) );
228 for (
int i = 0; i < reportNodes.size(); ++i )
230 const QString layoutName = reportNodes.at( i ).toElement().attribute( QStringLiteral(
"name" ) );
233 std::unique_ptr< QgsReport > r = std::make_unique< QgsReport >( mProject );
234 if ( !r->readLayoutXml( reportNodes.at( i ).toElement(), doc, context ) )
249 QDomElement layoutsElem = doc.createElement( QStringLiteral(
"Layouts" ) );
255 QDomElement layoutElem = l->writeLayoutXml( doc, context );
256 layoutsElem.appendChild( layoutElem );
266 std::unique_ptr< QgsMasterLayoutInterface > newLayout( layout->
clone() );
272 newLayout->setName( newName );
288 names.reserve( mLayouts.size() );
295 while ( name.isEmpty() || names.contains( name ) )
300 name = tr(
"Layout %1" ).arg(
id );
303 name = tr(
"Report %1" ).arg(
id );
313 if ( mLayouts.empty() )
322 if ( !l->layoutAccept( visitor ) )
339 : QAbstractListModel( parent )
340 , mLayoutManager( manager )
352 return ( mLayoutManager ? mLayoutManager->
layouts().count() : 0 ) + ( mAllowEmpty ? 1 : 0 );
357 if ( index.row() < 0 || index.row() >=
rowCount( QModelIndex() ) )
360 const bool isEmpty = index.row() == 0 && mAllowEmpty;
361 const int layoutRow = mAllowEmpty ? index.row() - 1 : index.row();
365 case Qt::DisplayRole:
366 case Qt::ToolTipRole:
368 return !isEmpty && mLayoutManager ? mLayoutManager->
layouts().at( layoutRow )->name() : QVariant();
372 if ( isEmpty || !mLayoutManager )
375 return QVariant::fromValue( l );
376 else if ( QgsReport *r =
dynamic_cast< QgsReport *
>( mLayoutManager->
layouts().at( layoutRow ) ) )
377 return QVariant::fromValue( r );
382 case Qt::DecorationRole:
384 return isEmpty || !mLayoutManager ? QIcon() : mLayoutManager->
layouts().at( layoutRow )->icon();
394 if ( !index.isValid() || role != Qt::EditRole )
398 if ( index.row() >= mLayoutManager->
layouts().count() )
403 if ( index.row() == 0 && mAllowEmpty )
406 if ( value.toString().isEmpty() )
414 bool changed = layout->
name() != value.toString();
419 QStringList layoutNames;
423 layoutNames << l->name();
425 if ( layoutNames.contains( value.toString() ) )
428 QMessageBox::warning(
nullptr, tr(
"Rename Layout" ), tr(
"There is already a layout named “%1”." ).arg( value.toString() ) );
432 layout->
setName( value.toString() );
438 Qt::ItemFlags
flags = QAbstractListModel::flags( index );
440 if ( index.isValid() )
442 return flags | Qt::ItemIsEditable;
454 if ( index.row() == 0 && mAllowEmpty )
459 else if ( QgsReport *r = qobject_cast< QgsReport * >( qvariant_cast<QObject *>(
data( index,
LayoutRole ) ) ) )
467 if ( !mLayoutManager )
469 return QModelIndex();
472 const int r = mLayoutManager->
layouts().indexOf( layout );
474 return QModelIndex();
476 QModelIndex idx = index( mAllowEmpty ? r + 1 : r, 0, QModelIndex() );
482 return QModelIndex();
487 if ( allowEmpty == mAllowEmpty )
492 beginInsertRows( QModelIndex(), 0, 0 );
498 beginRemoveRows( QModelIndex(), 0, 0 );
504void QgsLayoutManagerModel::layoutAboutToBeAdded(
const QString & )
506 int row = mLayoutManager->
layouts().count() + ( mAllowEmpty ? 1 : 0 );
507 beginInsertRows( QModelIndex(), row, row );
510void QgsLayoutManagerModel::layoutAboutToBeRemoved(
const QString &name )
513 int row = mLayoutManager->
layouts().indexOf( l ) + ( mAllowEmpty ? 1 : 0 );
515 beginRemoveRows( QModelIndex(), row, row );
518void QgsLayoutManagerModel::layoutAdded(
const QString & )
523void QgsLayoutManagerModel::layoutRemoved(
const QString & )
530 int row = mLayoutManager->
layouts().indexOf( layout ) + ( mAllowEmpty ? 1 : 0 );
531 QModelIndex index = createIndex( row, 0 );
532 emit dataChanged( index, index, QVector<int>() << Qt::DisplayRole );
540 : QSortFilterProxyModel( parent )
542 setDynamicSortFilter(
true );
544 setSortCaseSensitivity( Qt::CaseInsensitive );
549 const QString leftText = sourceModel()->data( left, Qt::DisplayRole ).toString();
550 const QString rightText = sourceModel()->data( right, Qt::DisplayRole ).toString();
551 if ( leftText.isEmpty() )
553 if ( rightText.isEmpty() )
556 return QString::localeAwareCompare( leftText, rightText ) < 0;
569 if ( !mFilterString.trimmed().isEmpty() )
571 if ( !layout->
name().contains( mFilterString, Qt::CaseInsensitive ) )
598 mFilterString = filter;
static std::unique_ptr< QgsPrintLayout > createLayoutFromCompositionXml(const QDomElement &composerElement, QgsProject *project)
createLayoutFromCompositionXml is a factory that creates layout instances from a QGIS 2....
List model representing the print layouts and reports available in a layout manager.
bool setData(const QModelIndex &index, const QVariant &value, int role=Qt::EditRole) override
QModelIndex indexFromLayout(QgsMasterLayoutInterface *layout) const
Returns the model index corresponding to a layout.
@ LayoutRole
Layout object.
Qt::ItemFlags flags(const QModelIndex &index) const override
QgsMasterLayoutInterface * layoutFromIndex(const QModelIndex &index) const
Returns the layout at the corresponding index.
void setAllowEmptyLayout(bool allowEmpty)
Sets whether an optional empty layout ("not set") option is present in the model.
QVariant data(const QModelIndex &index, int role) const override
bool allowEmptyLayout() const
Returns true if the model allows the empty layout ("not set") choice.
QgsLayoutManagerModel(QgsLayoutManager *manager, QObject *parent=nullptr)
Constructor for QgsLayoutManagerModel, showing the layouts from the specified manager.
int rowCount(const QModelIndex &parent) const override
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...
void setFilters(QgsLayoutManagerProxyModel::Filters filters)
Sets the current filters used for filtering available layouts.
QgsLayoutManagerProxyModel::Filters filters() const
Returns the current filters used for filtering available layouts.
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override
@ FilterReports
Includes reports.
@ FilterPrintLayouts
Includes print layouts.
QgsLayoutManagerProxyModel(QObject *parent=nullptr)
Constructor for QgsLayoutManagerProxyModel.
Manages storage of a set of layouts.
bool readXml(const QDomElement &element, const QDomDocument &doc)
Reads the manager's state from a DOM element, restoring all layouts present in the XML document.
QgsLayoutManager(QgsProject *project=nullptr)
Constructor for QgsLayoutManager.
QList< QgsMasterLayoutInterface * > layouts() const
Returns a list of all layouts contained in the manager.
QList< QgsPrintLayout * > printLayouts() const
Returns a list of all print layouts contained in the manager.
void layoutAboutToBeRemoved(const QString &name)
Emitted when a layout is about to be removed from the manager.
~QgsLayoutManager() override
bool removeLayout(QgsMasterLayoutInterface *layout)
Removes a layout from the manager.
QgsMasterLayoutInterface * layoutByName(const QString &name) const
Returns the layout with a matching name, or nullptr if no matching layouts were found.
void clear()
Removes and deletes all layouts from the manager.
bool addLayout(QgsMasterLayoutInterface *layout)
Adds a layout to the manager.
void layoutAboutToBeAdded(const QString &name)
Emitted when a layout is about to be added to the manager.
bool accept(QgsStyleEntityVisitorInterface *visitor) const
Accepts the specified style entity visitor, causing it to visit all style entities associated within ...
void layoutRenamed(QgsMasterLayoutInterface *layout, const QString &newName)
Emitted when a layout is renamed.
void layoutRemoved(const QString &name)
Emitted when a layout was removed from the manager.
QDomElement writeXml(QDomDocument &doc) const
Returns a DOM element representing the state of the manager.
QString generateUniqueTitle(QgsMasterLayoutInterface::Type type=QgsMasterLayoutInterface::PrintLayout) const
Generates a unique title for a new layout of the specified type, which does not clash with any alread...
void layoutAdded(const QString &name)
Emitted when a layout has been added to the manager.
QgsMasterLayoutInterface * duplicateLayout(const QgsMasterLayoutInterface *layout, const QString &newName)
Duplicates an existing layout from the manager.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Interface for master layout type objects, such as print layouts and reports.
virtual QString name() const =0
Returns the layout's name.
virtual QgsMasterLayoutInterface::Type layoutType() const =0
Returns the master layout type.
@ Report
Report (QgsReport)
@ PrintLayout
Individual print layout (QgsPrintLayout)
virtual QgsMasterLayoutInterface * clone() const =0
Creates a clone of the layout.
virtual void setName(const QString &name)=0
Sets the layout's name.
Print layout, a QgsLayout subclass for static or atlas-based layouts.
void nameChanged(const QString &name)
Emitted when the layout's name is changed.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsPathResolver pathResolver() const
Returns path resolver object with considering whether the project uses absolute or relative paths and...
const QgsLayoutManager * layoutManager() const
Returns the project's layout manager, which manages print layouts, atlases and reports within the pro...
void setDirty(bool b=true)
Flag the project as dirty (modified).
The class is used as a container of context for various read/write operations on other objects.
void setPathResolver(const QgsPathResolver &resolver)
Sets up path resolver for conversion between relative and absolute paths.
Scoped object for logging of the runtime for a single operation or group of operations.
void switchTask(const QString &name)
Switches the current task managed by the scoped profile to a new task with the given name.
An interface for classes which can visit style entity (e.g.
@ Layouts
Layout collection.
virtual bool visitExit(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor stops visiting a node.
virtual bool visitEnter(const QgsStyleEntityVisitorInterface::Node &node)
Called when the visitor starts visiting a node.
Contains information relating to a node (i.e.