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.