QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
qgslayoutmanager.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslayoutmanager.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
16#include "qgslayoutmanager.h"
17
19#include "qgslayout.h"
20#include "qgslayoutundostack.h"
21#include "qgsprintlayout.h"
22#include "qgsproject.h"
23#include "qgsreadwritecontext.h"
24#include "qgsreport.h"
25#include "qgsruntimeprofiler.h"
27
28#include <QString>
29
30#include "moc_qgslayoutmanager.cpp"
31
32using namespace Qt::StringLiterals;
33
43
48
50{
51 return addObject( layout );
52}
53
55{
56 return removeObject( layout );
57}
58
63
64QList<QgsMasterLayoutInterface *> QgsLayoutManager::layouts() const
65{
66 return mObjects;
67}
68
69QList<QgsPrintLayout *> QgsLayoutManager::printLayouts() const
70{
71 QList<QgsPrintLayout *> result;
72 const QList<QgsMasterLayoutInterface *> constLayouts( mObjects );
73 result.reserve( constLayouts.size() );
74 for ( const auto &layout : constLayouts )
75 {
76 QgsPrintLayout *_item( dynamic_cast<QgsPrintLayout *>( layout ) );
77 if ( _item )
78 result.push_back( _item );
79 }
80 return result;
81}
82
84{
85 return objectByName( name );
86}
87
88bool QgsLayoutManager::readXml( const QDomElement &element, const QDomDocument &doc )
89{
90 clear();
91
92 QDomElement layoutsElem = element;
93 if ( element.tagName() != "Layouts"_L1 )
94 {
95 layoutsElem = element.firstChildElement( u"Layouts"_s );
96 }
97 if ( layoutsElem.isNull() )
98 {
99 // handle legacy projects
100 layoutsElem = doc.documentElement();
101 }
102
103 //restore each composer
104 bool result = true;
105 QDomNodeList composerNodes = element.elementsByTagName( u"Composer"_s );
106 QgsScopedRuntimeProfile profile( tr( "Loading QGIS 2.x compositions" ), u"projectload"_s );
107 for ( int i = 0; i < composerNodes.size(); ++i )
108 {
109 // This legacy title is the Composer "title" (that can be overridden by the Composition "name")
110 QString legacyTitle = composerNodes.at( i ).toElement().attribute( u"title"_s );
111 // Convert compositions to layouts
112 QDomNodeList compositionNodes = composerNodes.at( i ).toElement().elementsByTagName( u"Composition"_s );
113 for ( int j = 0; j < compositionNodes.size(); ++j )
114 {
115 std::unique_ptr< QgsPrintLayout > l( QgsCompositionConverter::createLayoutFromCompositionXml( compositionNodes.at( j ).toElement(), mProject ) );
116 if ( l )
117 {
118 if ( l->name().isEmpty() )
119 l->setName( legacyTitle );
120
121 // some 2.x projects could end in a state where they had duplicated layout names. This is strictly forbidden in 3.x
122 // so check for duplicate name in layouts already added
123 int id = 2;
124 bool isDuplicateName = false;
125 QString originalName = l->name();
126 do
127 {
128 isDuplicateName = false;
129 for ( QgsMasterLayoutInterface *layout : std::as_const( mObjects ) )
130 {
131 if ( l->name() == layout->name() )
132 {
133 isDuplicateName = true;
134 break;
135 }
136 }
137 if ( isDuplicateName )
138 {
139 l->setName( u"%1 %2"_s.arg( originalName ).arg( id ) );
140 id++;
141 }
142 }
143 while ( isDuplicateName );
144
145 bool added = addLayout( l.release() );
146 result = added && result;
147 }
148 }
149 }
150
151 QgsReadWriteContext context;
152 context.setPathResolver( mProject->pathResolver() );
153
154 profile.switchTask( tr( "Creating layouts" ) );
155
156 // restore layouts
157 const QDomNodeList layoutNodes = layoutsElem.childNodes();
158 for ( int i = 0; i < layoutNodes.size(); ++i )
159 {
160 if ( layoutNodes.at( i ).nodeName() != "Layout"_L1 )
161 continue;
162
163 const QString layoutName = layoutNodes.at( i ).toElement().attribute( u"name"_s );
164 QgsScopedRuntimeProfile profile( layoutName, u"projectload"_s );
165
166 auto l = std::make_unique< QgsPrintLayout >( mProject );
167 l->undoStack()->blockCommands( true );
168 if ( !l->readLayoutXml( layoutNodes.at( i ).toElement(), doc, context ) )
169 {
170 result = false;
171 continue;
172 }
173 l->undoStack()->blockCommands( false );
174 if ( !addLayout( l.release() ) )
175 {
176 result = false;
177 }
178 }
179 //reports
180 profile.switchTask( tr( "Creating reports" ) );
181 const QDomNodeList reportNodes = element.elementsByTagName( u"Report"_s );
182 for ( int i = 0; i < reportNodes.size(); ++i )
183 {
184 const QString layoutName = reportNodes.at( i ).toElement().attribute( u"name"_s );
185 QgsScopedRuntimeProfile profile( layoutName, u"projectload"_s );
186
187 auto r = std::make_unique< QgsReport >( mProject );
188 if ( !r->readLayoutXml( reportNodes.at( i ).toElement(), doc, context ) )
189 {
190 result = false;
191 continue;
192 }
193 if ( !addLayout( r.release() ) )
194 {
195 result = false;
196 }
197 }
198 return result;
199}
200
201QDomElement QgsLayoutManager::writeXml( QDomDocument &doc ) const
202{
203 QDomElement layoutsElem = doc.createElement( u"Layouts"_s );
204
205 QgsReadWriteContext context;
206 context.setPathResolver( mProject->pathResolver() );
208 {
209 QDomElement layoutElem = l->writeLayoutXml( doc, context );
210 layoutsElem.appendChild( layoutElem );
211 }
212 return layoutsElem;
213}
214
216{
217 if ( !layout )
218 return nullptr;
219
220 std::unique_ptr< QgsMasterLayoutInterface > newLayout( layout->clone() );
221 if ( !newLayout )
222 {
223 return nullptr;
224 }
225
226 newLayout->setName( newName );
227 QgsMasterLayoutInterface *l = newLayout.get();
228 if ( !addLayout( newLayout.release() ) )
229 {
230 return nullptr;
231 }
232 else
233 {
234 // cppcheck-suppress returnDanglingLifetime
235 return l;
236 }
237}
238
240{
241 QStringList names;
242 names.reserve( mObjects.size() );
244 {
245 names << l->name();
246 }
247 QString name;
248 int id = 1;
249 while ( name.isEmpty() || names.contains( name ) )
250 {
251 switch ( type )
252 {
254 name = tr( "Layout %1" ).arg( id );
255 break;
257 name = tr( "Report %1" ).arg( id );
258 break;
259 }
260 id++;
261 }
262 return name;
263}
264
266{
267 if ( mObjects.empty() )
268 return true;
269
270 // NOTE: if visitEnter returns false it means "don't visit the layouts", not "abort all further visitations"
272 return true;
273
275 {
276 if ( !l->layoutAccept( visitor ) )
277 return false;
278 }
279
281 return false;
282
283 return true;
284}
285
287{
288 // ugly, but unavoidable for interfaces...
289 if ( QgsPrintLayout *l = dynamic_cast< QgsPrintLayout * >( layout ) )
290 {
291 connect( l, &QgsPrintLayout::nameChanged, this, [this, l]( const QString & newName )
292 {
293 emit layoutRenamed( l, newName );
294 } );
295 }
296 else if ( QgsReport *r = dynamic_cast< QgsReport * >( layout ) )
297 {
298 connect( r, &QgsReport::nameChanged, this, [this, r]( const QString & newName )
299 {
300 emit layoutRenamed( r, newName );
301 } );
302 }
303}
QgsMasterLayoutInterface * objectByName(const QString &name) const
static std::unique_ptr< QgsPrintLayout > createLayoutFromCompositionXml(const QDomElement &composerElement, QgsProject *project)
createLayoutFromCompositionXml is a factory that creates layout instances from a QGIS 2....
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 setupObjectConnections(QgsMasterLayoutInterface *layout) override
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.
Interface for master layout type objects, such as print layouts and reports.
@ PrintLayout
Individual print layout (QgsPrintLayout).
virtual QgsMasterLayoutInterface * clone() const =0
Creates a clone of the layout.
Print layout, a QgsLayout subclass for static or atlas-based layouts.
void nameChanged(const QString &name)
Emitted when the layout's name is changed.
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.
Encapsulates a QGIS project, including sets of map layers and their styles, layouts,...
Definition qgsproject.h:112
A container for the context for various read/write operations on 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.
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.