27 #include <QMessageBox>
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 );
287 names.reserve( mLayouts.size() );
294 while ( name.isEmpty() || names.contains( name ) )
299 name = tr(
"Layout %1" ).arg(
id );
302 name = tr(
"Report %1" ).arg(
id );
312 if ( mLayouts.empty() )
321 if ( !l->layoutAccept( visitor ) )
338 : QAbstractListModel( parent )
339 , mLayoutManager( manager )
351 return ( mLayoutManager ? mLayoutManager->
layouts().count() : 0 ) + ( mAllowEmpty ? 1 : 0 );
356 if ( index.row() < 0 || index.row() >=
rowCount( QModelIndex() ) )
359 const bool isEmpty = index.row() == 0 && mAllowEmpty;
360 const int layoutRow = mAllowEmpty ? index.row() - 1 : index.row();
364 case Qt::DisplayRole:
365 case Qt::ToolTipRole:
367 return !isEmpty && mLayoutManager ? mLayoutManager->
layouts().at( layoutRow )->name() : QVariant();
371 if ( isEmpty || !mLayoutManager )
374 return QVariant::fromValue( l );
375 else if ( QgsReport *r =
dynamic_cast< QgsReport *
>( mLayoutManager->
layouts().at( layoutRow ) ) )
376 return QVariant::fromValue( r );
381 case Qt::DecorationRole:
383 return isEmpty || !mLayoutManager ? QIcon() : mLayoutManager->
layouts().at( layoutRow )->icon();
393 if ( !index.isValid() || role != Qt::EditRole )
397 if ( index.row() >= mLayoutManager->
layouts().count() )
402 if ( index.row() == 0 && mAllowEmpty )
405 if ( value.toString().isEmpty() )
413 bool changed = layout->
name() != value.toString();
418 QStringList layoutNames;
422 layoutNames << l->name();
424 if ( layoutNames.contains( value.toString() ) )
427 QMessageBox::warning(
nullptr, tr(
"Rename Layout" ), tr(
"There is already a layout named “%1”." ).arg( value.toString() ) );
431 layout->
setName( value.toString() );
437 Qt::ItemFlags
flags = QAbstractListModel::flags( index );
439 if ( index.isValid() )
441 return flags | Qt::ItemIsEditable;
453 if ( index.row() == 0 && mAllowEmpty )
458 else if ( QgsReport *r = qobject_cast< QgsReport * >( qvariant_cast<QObject *>(
data( index,
LayoutRole ) ) ) )
466 if ( !mLayoutManager )
468 return QModelIndex();
471 const int r = mLayoutManager->
layouts().indexOf( layout );
473 return QModelIndex();
475 QModelIndex idx = index( mAllowEmpty ? r + 1 : r, 0, QModelIndex() );
481 return QModelIndex();
486 if ( allowEmpty == mAllowEmpty )
491 beginInsertRows( QModelIndex(), 0, 0 );
497 beginRemoveRows( QModelIndex(), 0, 0 );
503 void QgsLayoutManagerModel::layoutAboutToBeAdded(
const QString & )
505 int row = mLayoutManager->
layouts().count() + ( mAllowEmpty ? 1 : 0 );
506 beginInsertRows( QModelIndex(), row, row );
509 void QgsLayoutManagerModel::layoutAboutToBeRemoved(
const QString &name )
512 int row = mLayoutManager->
layouts().indexOf( l ) + ( mAllowEmpty ? 1 : 0 );
514 beginRemoveRows( QModelIndex(), row, row );
517 void QgsLayoutManagerModel::layoutAdded(
const QString & )
522 void QgsLayoutManagerModel::layoutRemoved(
const QString & )
529 int row = mLayoutManager->
layouts().indexOf( layout ) + ( mAllowEmpty ? 1 : 0 );
530 QModelIndex index = createIndex( row, 0 );
531 emit dataChanged( index, index, QVector<int>() << Qt::DisplayRole );
539 : QSortFilterProxyModel( parent )
541 setDynamicSortFilter(
true );
543 setSortCaseSensitivity( Qt::CaseInsensitive );
548 const QString leftText = sourceModel()->data( left, Qt::DisplayRole ).toString();
549 const QString rightText = sourceModel()->data( right, Qt::DisplayRole ).toString();
550 if ( leftText.isEmpty() )
552 if ( rightText.isEmpty() )
555 return QString::localeAwareCompare( leftText, rightText ) < 0;
568 if ( !mFilterString.trimmed().isEmpty() )
570 if ( !layout->
name().contains( mFilterString, Qt::CaseInsensitive ) )
597 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.