mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-14 00:07:35 -04:00
More work on porting multiframe items
This commit is contained in:
parent
2cf99116d7
commit
dddce25e13
@ -175,9 +175,18 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb
|
||||
%Docstring
|
||||
Returns the layout item with matching ``uuid`` unique identifier, or a None
|
||||
if a matching item could not be found.
|
||||
.. seealso:: multiFrameByUuid()
|
||||
:rtype: QgsLayoutItem
|
||||
%End
|
||||
|
||||
QgsLayoutMultiFrame *multiFrameByUuid( const QString &uuid ) const;
|
||||
%Docstring
|
||||
Returns the layout multiframe with matching ``uuid`` unique identifier, or a None
|
||||
if a matching multiframe could not be found.
|
||||
.. seealso:: itemByUuid()
|
||||
:rtype: QgsLayoutMultiFrame
|
||||
%End
|
||||
|
||||
QgsLayoutItem *layoutItemAt( QPointF position, const bool ignoreLocked = false ) const;
|
||||
%Docstring
|
||||
Returns the topmost layout item at a specified ``position``. Ignores paper items.
|
||||
|
@ -9,6 +9,108 @@
|
||||
|
||||
|
||||
|
||||
class QgsLayoutFrame: QgsLayoutItem
|
||||
{
|
||||
%Docstring
|
||||
Base class for frame items, which form a layout multiframe item.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgslayoutframe.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsLayoutFrame( QgsLayout *layout, QgsLayoutMultiFrame *multiFrame );
|
||||
%Docstring
|
||||
Constructor for QgsLayoutFrame, with the specified parent ``layout``
|
||||
and belonging to a ``multiFrame``.
|
||||
%End
|
||||
|
||||
static QgsLayoutFrame *create( QgsLayout *layout ) /Factory/;
|
||||
%Docstring
|
||||
Creates a new QgsLayoutFrame belonging to the specified ``layout``.
|
||||
:rtype: QgsLayoutFrame
|
||||
%End
|
||||
|
||||
virtual int type() const;
|
||||
|
||||
virtual QString stringType() const;
|
||||
|
||||
|
||||
virtual QString displayName() const;
|
||||
|
||||
|
||||
void setContentSection( const QRectF §ion );
|
||||
%Docstring
|
||||
Sets the visible part of the multiframe's content which is visible within
|
||||
this frame (relative to the total multiframe extent in layout units).
|
||||
.. seealso:: extent()
|
||||
%End
|
||||
|
||||
QgsLayoutMultiFrame *multiFrame() const;
|
||||
%Docstring
|
||||
Returns the parent multiframe for the frame.
|
||||
:rtype: QgsLayoutMultiFrame
|
||||
%End
|
||||
|
||||
|
||||
QRectF extent() const;
|
||||
%Docstring
|
||||
Returns the visible portion of the multi frame's content which
|
||||
is shown in this frame, in layout units.
|
||||
.. seealso:: setContentSection()
|
||||
:rtype: QRectF
|
||||
%End
|
||||
|
||||
bool hidePageIfEmpty() const;
|
||||
%Docstring
|
||||
Returns whether the page should be hidden (ie, not included in layout exports) if this frame is empty
|
||||
:return: true if page should be hidden if frame is empty
|
||||
.. seealso:: setHidePageIfEmpty()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
void setHidePageIfEmpty( const bool hidePageIfEmpty );
|
||||
%Docstring
|
||||
Sets whether the page should be hidden (ie, not included in layout exports) if this frame is empty
|
||||
\param hidePageIfEmpty set to true if page should be hidden if frame is empty
|
||||
.. seealso:: hidePageIfEmpty()
|
||||
%End
|
||||
|
||||
bool hideBackgroundIfEmpty() const;
|
||||
%Docstring
|
||||
Returns whether the background and frame stroke should be hidden if this frame is empty
|
||||
:return: true if background and stroke should be hidden if frame is empty
|
||||
.. seealso:: setHideBackgroundIfEmpty()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
void setHideBackgroundIfEmpty( const bool hideBackgroundIfEmpty );
|
||||
%Docstring
|
||||
Sets whether the background and frame stroke should be hidden if this frame is empty
|
||||
\param hideBackgroundIfEmpty set to true if background and stroke should be hidden if frame is empty
|
||||
.. seealso:: hideBackgroundIfEmpty()
|
||||
%End
|
||||
|
||||
bool isEmpty() const;
|
||||
%Docstring
|
||||
Returns whether the frame is empty.
|
||||
.. seealso:: hidePageIfEmpty()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
virtual QgsExpressionContext createExpressionContext() const;
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
virtual void draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle = 0 );
|
||||
|
||||
void drawFrame( QgsRenderContext &context );
|
||||
void drawBackground( QgsRenderContext &context );
|
||||
|
||||
};
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
|
@ -74,6 +74,70 @@ class QgsLayoutItemAbstractMetadata
|
||||
|
||||
|
||||
|
||||
class QgsLayoutMultiFrameAbstractMetadata
|
||||
{
|
||||
%Docstring
|
||||
Stores metadata about one layout multiframe class.
|
||||
|
||||
A companion class, QgsLayoutMultiFrameAbstractGuiMetadata, handles the
|
||||
GUI behavior of QgsLayoutMultiFrames.
|
||||
|
||||
.. note::
|
||||
|
||||
In C++ you can use QgsLayoutMultiFrameMetadata convenience class.
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgslayoutitemregistry.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
QgsLayoutMultiFrameAbstractMetadata( int type, const QString &visibleName );
|
||||
%Docstring
|
||||
Constructor for QgsLayoutMultiFrameAbstractMetadata with the specified class ``type``
|
||||
and ``visibleName``.
|
||||
%End
|
||||
|
||||
virtual ~QgsLayoutMultiFrameAbstractMetadata();
|
||||
|
||||
int type() const;
|
||||
%Docstring
|
||||
Returns the unique item type code for the layout multiframe class.
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
virtual QIcon icon() const;
|
||||
%Docstring
|
||||
Returns an icon representing the layout multiframe type.
|
||||
:rtype: QIcon
|
||||
%End
|
||||
|
||||
QString visibleName() const;
|
||||
%Docstring
|
||||
Returns a translated, user visible name for the layout multiframe class.
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
virtual QgsLayoutMultiFrame *createMultiFrame( QgsLayout *layout ) = 0 /Factory/;
|
||||
%Docstring
|
||||
Creates a layout multiframe of this class for a specified ``layout``.
|
||||
:rtype: QgsLayoutMultiFrame
|
||||
%End
|
||||
|
||||
virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving );
|
||||
%Docstring
|
||||
Resolve paths in the item's ``properties`` (if there are any paths).
|
||||
When ``saving`` is true, paths are converted from absolute to relative,
|
||||
when ``saving`` is false, paths are converted from relative to absolute.
|
||||
This ensures that paths in project files can be relative, but in item
|
||||
instances the paths are always absolute.
|
||||
%End
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
class QgsLayoutItemRegistry : QObject
|
||||
@ -111,6 +175,9 @@ class QgsLayoutItemRegistry : QObject
|
||||
LayoutPolyline,
|
||||
LayoutFrame,
|
||||
|
||||
// known
|
||||
LayoutHtml,
|
||||
|
||||
// item
|
||||
PluginItem,
|
||||
};
|
||||
@ -139,21 +206,46 @@ class QgsLayoutItemRegistry : QObject
|
||||
%Docstring
|
||||
Returns the metadata for the specified item ``type``. Returns None if
|
||||
a corresponding type was not found in the registry.
|
||||
.. seealso:: multiFrameMetadata()
|
||||
:rtype: QgsLayoutItemAbstractMetadata
|
||||
%End
|
||||
|
||||
QgsLayoutMultiFrameAbstractMetadata *multiFrameMetadata( int type ) const;
|
||||
%Docstring
|
||||
Returns the metadata for the specified multiframe ``type``. Returns None if
|
||||
a corresponding type was not found in the registry.
|
||||
.. seealso:: itemMetadata()
|
||||
:rtype: QgsLayoutMultiFrameAbstractMetadata
|
||||
%End
|
||||
|
||||
bool addLayoutItemType( QgsLayoutItemAbstractMetadata *metadata /Transfer/ );
|
||||
%Docstring
|
||||
Registers a new layout item type. Takes ownership of the metadata instance.
|
||||
.. seealso:: addLayoutMultiFrameType()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
bool addLayoutMultiFrameType( QgsLayoutMultiFrameAbstractMetadata *metadata /Transfer/ );
|
||||
%Docstring
|
||||
Registers a new layout multiframe type. Takes ownership of the metadata instance.
|
||||
.. seealso:: addLayoutItemType()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
QgsLayoutItem *createItem( int type, QgsLayout *layout ) const /Factory/;
|
||||
%Docstring
|
||||
Creates a new instance of a layout item given the item ``type``, and target ``layout``.
|
||||
.. seealso:: createMultiFrame()
|
||||
:rtype: QgsLayoutItem
|
||||
%End
|
||||
|
||||
QgsLayoutMultiFrame *createMultiFrame( int type, QgsLayout *layout ) const /Factory/;
|
||||
%Docstring
|
||||
Creates a new instance of a layout multiframe given the multiframe ``type``, and target ``layout``.
|
||||
.. seealso:: createItem()
|
||||
:rtype: QgsLayoutMultiFrame
|
||||
%End
|
||||
|
||||
void resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const;
|
||||
%Docstring
|
||||
Resolve paths in properties of a particular symbol layer.
|
||||
@ -175,6 +267,12 @@ class QgsLayoutItemRegistry : QObject
|
||||
``type`` and visible ``name``.
|
||||
%End
|
||||
|
||||
void multiFrameTypeAdded( int type, const QString &name );
|
||||
%Docstring
|
||||
Emitted whenever a new multiframe type is added to the registry, with the specified
|
||||
``type`` and visible ``name``.
|
||||
%End
|
||||
|
||||
private:
|
||||
QgsLayoutItemRegistry( const QgsLayoutItemRegistry &rh );
|
||||
};
|
||||
|
@ -10,6 +10,331 @@
|
||||
|
||||
|
||||
|
||||
class QgsLayoutMultiFrame: QgsLayoutObject, QgsLayoutUndoObjectInterface
|
||||
{
|
||||
%Docstring
|
||||
Abstract base class for layout items with the ability to distribute the content to
|
||||
several frames (QgsLayoutFrame items).
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
%TypeHeaderCode
|
||||
#include "qgslayoutmultiframe.h"
|
||||
%End
|
||||
public:
|
||||
|
||||
enum ResizeMode
|
||||
{
|
||||
UseExistingFrames,
|
||||
ExtendToNextPage,
|
||||
RepeatOnEveryPage,
|
||||
RepeatUntilFinished
|
||||
};
|
||||
|
||||
enum UndoCommand
|
||||
{
|
||||
UndoNone,
|
||||
};
|
||||
|
||||
QgsLayoutMultiFrame( QgsLayout *layout /TransferThis/ );
|
||||
%Docstring
|
||||
Construct a new multiframe item, attached to the specified ``layout``.
|
||||
%End
|
||||
|
||||
~QgsLayoutMultiFrame();
|
||||
|
||||
QString uuid() const;
|
||||
%Docstring
|
||||
Returns the multiframe identification string. This is a unique random string set for the multiframe
|
||||
upon creation.
|
||||
.. note::
|
||||
|
||||
There is no corresponding setter for the uuid - it's created automatically.
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
virtual QSizeF totalSize() const = 0;
|
||||
%Docstring
|
||||
Returns the total size of the multiframe's content, in layout units.
|
||||
:rtype: QSizeF
|
||||
%End
|
||||
|
||||
virtual int type() const = 0;
|
||||
%Docstring
|
||||
Returns unique multiframe type id.
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
virtual QString stringType() const = 0;
|
||||
%Docstring
|
||||
Return the multiframe type as a string.
|
||||
|
||||
This string must be a unique, single word, character only representation of the item type, eg "LayoutHtml"
|
||||
.. seealso:: type()
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
virtual QSizeF fixedFrameSize( const int frameIndex = -1 ) const;
|
||||
%Docstring
|
||||
Returns the fixed size for a frame, if desired. If the fixed frame size changes,
|
||||
the sizes of all frames can be recalculated by calling recalculateFrameRects().
|
||||
\param frameIndex frame number
|
||||
:return: fixed size for frame. If the size has a width or height of 0, then
|
||||
the frame size is not fixed in that direction and frames can have variable width
|
||||
or height accordingly.
|
||||
.. seealso:: minFrameSize()
|
||||
.. seealso:: recalculateFrameRects()
|
||||
:rtype: QSizeF
|
||||
%End
|
||||
|
||||
virtual QSizeF minFrameSize( const int frameIndex = -1 ) const;
|
||||
%Docstring
|
||||
Returns the minimum size for a frames, if desired. If the minimum
|
||||
size changes, the sizes of all frames can be recalculated by calling
|
||||
recalculateFrameRects().
|
||||
\param frameIndex frame number
|
||||
:return: minimum size for frame. If the size has a width or height of 0, then
|
||||
the frame size has no minimum in that direction.
|
||||
.. seealso:: fixedFrameSize()
|
||||
.. seealso:: recalculateFrameRects()
|
||||
:rtype: QSizeF
|
||||
%End
|
||||
|
||||
virtual void render( QgsRenderContext &context, const QRectF &renderExtent, const int frameIndex,
|
||||
const QStyleOptionGraphicsItem *itemStyle = 0 ) = 0;
|
||||
%Docstring
|
||||
Renders a portion of the multiframe's content into a render ``context``.
|
||||
\param context destination render painter
|
||||
\param renderExtent visible extent of content to render into the painter.
|
||||
\param frameIndex frame number for content
|
||||
\param itemStyle item style options for graphics item rendering
|
||||
%End
|
||||
|
||||
virtual void addFrame( QgsLayoutFrame *frame /Transfer/, bool recalcFrameSizes = true );
|
||||
%Docstring
|
||||
Adds a ``frame`` to the multiframe.
|
||||
|
||||
If ``recalcFrameSizes`` is set to true, then a recalculation of all existing frame sizes will be forced.
|
||||
|
||||
.. seealso:: removeFrame()
|
||||
%End
|
||||
|
||||
virtual double findNearbyPageBreak( double yPos );
|
||||
%Docstring
|
||||
Finds the optimal position to break a frame at.
|
||||
\param yPos maximum vertical position for break, in layout units.
|
||||
:return: the optimal breakable position which occurs in the multi frame close
|
||||
to and before the specified yPos
|
||||
:rtype: float
|
||||
%End
|
||||
|
||||
void removeFrame( int index, bool removeEmptyPages = false );
|
||||
%Docstring
|
||||
Removes a frame by ``index`` from the multiframe. This method automatically removes the frame from the
|
||||
layout too.
|
||||
|
||||
If ``removeEmptyPages`` is set to true, then pages which are empty after the frame is removed will
|
||||
also be removed from the layout.
|
||||
|
||||
.. seealso:: addFrame()
|
||||
.. seealso:: deleteFrames()
|
||||
%End
|
||||
|
||||
void deleteFrames();
|
||||
%Docstring
|
||||
Removes and deletes all child frames.
|
||||
.. seealso:: removeFrame()
|
||||
%End
|
||||
|
||||
void setResizeMode( ResizeMode mode );
|
||||
%Docstring
|
||||
Sets the resize ``mode`` for the multiframe, and recalculates frame sizes to match.
|
||||
.. seealso:: resizeMode()
|
||||
%End
|
||||
|
||||
ResizeMode resizeMode() const;
|
||||
%Docstring
|
||||
Returns the resize mode for the multiframe.
|
||||
.. seealso:: setResizeMode()
|
||||
:rtype: ResizeMode
|
||||
%End
|
||||
|
||||
bool writeXml( QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context, bool ignoreFrames = false ) const;
|
||||
%Docstring
|
||||
Stores the multiframe state in a DOM element.
|
||||
\param parentElement parent DOM element (e.g. 'Layout' element)
|
||||
\param document DOM document
|
||||
\param context read write context
|
||||
\param ignoreFrames set to false to avoid writing state information about child frames into DOM
|
||||
.. seealso:: readXml()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
bool readXml( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context, bool ignoreFrames = false );
|
||||
%Docstring
|
||||
Sets the item state from a DOM element.
|
||||
\param itemElement is the DOM node corresponding to item (e.g. 'LayoutItem' element)
|
||||
\param document DOM document
|
||||
\param context read write context
|
||||
\param ignoreFrames set to false to avoid read state information about child frames from DOM
|
||||
.. seealso:: writeXml()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
QList<QgsLayoutFrame *> frames() const;
|
||||
%Docstring
|
||||
Returns a list of all child frames for this multiframe.
|
||||
.. seealso:: frameCount()
|
||||
:rtype: list of QgsLayoutFrame
|
||||
%End
|
||||
|
||||
int frameCount() const;
|
||||
%Docstring
|
||||
Returns the number of frames associated with this multiframe.
|
||||
.. seealso:: frames()
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
QgsLayoutFrame *frame( int index ) const;
|
||||
%Docstring
|
||||
Returns the child frame at a specified ``index`` from the multiframe.
|
||||
.. seealso:: frameIndex()
|
||||
:rtype: QgsLayoutFrame
|
||||
%End
|
||||
|
||||
int frameIndex( QgsLayoutFrame *frame ) const;
|
||||
%Docstring
|
||||
Returns the index of a ``frame`` within the multiframe.
|
||||
:return: index for frame if found, -1 if frame not found in multiframe
|
||||
.. seealso:: frame()
|
||||
:rtype: int
|
||||
%End
|
||||
|
||||
QgsLayoutFrame *createNewFrame( QgsLayoutFrame *currentFrame, QPointF pos, QSizeF size );
|
||||
%Docstring
|
||||
Creates a new frame and adds it to the multi frame and layout.
|
||||
\param currentFrame an existing QgsLayoutFrame from which to copy the size
|
||||
and general frame properties (e.g., frame style, background, rendering settings).
|
||||
\param pos position of top-left corner of the new frame, in layout units
|
||||
\param size size of the new frame, in layout units
|
||||
:rtype: QgsLayoutFrame
|
||||
%End
|
||||
|
||||
virtual QString displayName() const;
|
||||
%Docstring
|
||||
Returns the multiframe display name.
|
||||
:rtype: str
|
||||
%End
|
||||
|
||||
virtual QgsAbstractLayoutUndoCommand *createCommand( const QString &text, int id, QUndoCommand *parent = 0 ) /Factory/;
|
||||
|
||||
|
||||
void beginCommand( const QString &commandText, UndoCommand command = UndoNone );
|
||||
%Docstring
|
||||
Starts new undo command for this item.
|
||||
The ``commandText`` should be a capitalized, imperative tense description (e.g. "Add Map Item").
|
||||
If specified, multiple consecutive commands for this item with the same ``command`` will
|
||||
be collapsed into a single undo command in the layout history.
|
||||
.. seealso:: endCommand()
|
||||
.. seealso:: cancelCommand()
|
||||
%End
|
||||
|
||||
void endCommand();
|
||||
%Docstring
|
||||
Completes the current item command and push it onto the layout's undo stack.
|
||||
.. seealso:: beginCommand()
|
||||
.. seealso:: cancelCommand()
|
||||
%End
|
||||
|
||||
void cancelCommand();
|
||||
%Docstring
|
||||
Cancels the current item command and discards it.
|
||||
.. seealso:: beginCommand()
|
||||
.. seealso:: endCommand()
|
||||
%End
|
||||
|
||||
public slots:
|
||||
|
||||
void update();
|
||||
%Docstring
|
||||
Forces a redraw of all child frames.
|
||||
%End
|
||||
|
||||
virtual void recalculateFrameSizes();
|
||||
%Docstring
|
||||
Recalculates the portion of the multiframe item which is shown in each of its
|
||||
component frames. If the resize mode is set to anything but UseExistingFrames then
|
||||
this may cause new frames to be added or frames to be removed, in order to fit
|
||||
the current size of the multiframe's content.
|
||||
.. seealso:: recalculateFrameRects()
|
||||
%End
|
||||
|
||||
void recalculateFrameRects();
|
||||
%Docstring
|
||||
Forces a recalculation of all the associated frame's scene rectangles. This
|
||||
method is useful for multiframes which implement a minFrameSize() or
|
||||
fixedFrameSize() method.
|
||||
.. seealso:: minFrameSize()
|
||||
.. seealso:: fixedFrameSize()
|
||||
.. seealso:: recalculateFrameSizes
|
||||
%End
|
||||
|
||||
signals:
|
||||
|
||||
void changed();
|
||||
%Docstring
|
||||
Emitted when the properties of a multi frame have changed, and the GUI item widget
|
||||
must be updated.
|
||||
%End
|
||||
|
||||
void contentsChanged();
|
||||
%Docstring
|
||||
Emitted when the contents of the multi frame have changed and the frames
|
||||
must be redrawn.
|
||||
%End
|
||||
|
||||
protected:
|
||||
|
||||
virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
|
||||
%Docstring
|
||||
Stores multiframe state within an XML DOM element.
|
||||
\param element is the DOM element to store the multiframe's properties in
|
||||
\param document DOM document
|
||||
\param context read write context
|
||||
.. seealso:: writeXml()
|
||||
.. seealso:: readPropertiesFromElement()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );
|
||||
%Docstring
|
||||
Sets multiframe state from a DOM element.
|
||||
\param element is the DOM element for the multiframe
|
||||
\param document DOM document
|
||||
\param context read write context
|
||||
.. seealso:: writePropertiesToElement()
|
||||
.. seealso:: readXml()
|
||||
:rtype: bool
|
||||
%End
|
||||
|
||||
|
||||
|
||||
protected slots:
|
||||
|
||||
void handlePageChange();
|
||||
%Docstring
|
||||
Adapts to changed number of layout pages if resize type is RepeatOnEveryPage.
|
||||
%End
|
||||
|
||||
void handleFrameRemoval();
|
||||
%Docstring
|
||||
Called when a frame is removed. Updates frame list and recalculates
|
||||
content of remaining frames.
|
||||
%End
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/************************************************************************
|
||||
* This file has been generated automatically from *
|
||||
|
@ -33,6 +33,8 @@
|
||||
#include "qgslayoutlabelwidget.h"
|
||||
#include "qgslayoutitemlegend.h"
|
||||
#include "qgslayoutlegendwidget.h"
|
||||
#include "qgslayoutframe.h"
|
||||
#include "qgslayoutitemhtml.h"
|
||||
#include "qgisapp.h"
|
||||
#include "qgsmapcanvas.h"
|
||||
|
||||
@ -198,4 +200,23 @@ void QgsLayoutAppUtils::registerGuiForKnownItemTypes()
|
||||
return band.release();
|
||||
} );
|
||||
registry->addLayoutItemGuiMetadata( polylineMetadata.release() );
|
||||
|
||||
|
||||
// html item
|
||||
|
||||
auto htmlItemMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >( QgsLayoutItemRegistry::LayoutHtml, QObject::tr( "HTML" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddHtml.svg" ) ),
|
||||
[ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
|
||||
{
|
||||
return nullptr; //new QgsLayoutMapWidget( qobject_cast< QgsLayoutItemMap * >( item ) );
|
||||
}, createRubberBand );
|
||||
htmlItemMetadata->setItemCreationFunction( [ = ]( QgsLayout * layout )->QgsLayoutItem*
|
||||
{
|
||||
std::unique_ptr< QgsLayoutItemHtml > htmlMultiFrame = qgis::make_unique< QgsLayoutItemHtml >( layout );
|
||||
QgsLayoutItemHtml *html = htmlMultiFrame.get();
|
||||
layout->addMultiFrame( htmlMultiFrame.release() );
|
||||
std::unique_ptr< QgsLayoutFrame > frame = qgis::make_unique< QgsLayoutFrame >( layout, html );
|
||||
return frame.release();
|
||||
} );
|
||||
registry->addLayoutItemGuiMetadata( htmlItemMetadata.release() );
|
||||
|
||||
}
|
||||
|
@ -392,6 +392,7 @@ SET(QGIS_CORE_SRCS
|
||||
layout/qgslayoutmeasurementconverter.cpp
|
||||
layout/qgslayoutmodel.cpp
|
||||
layout/qgslayoutmultiframe.cpp
|
||||
layout/qgslayoutmultiframeundocommand.cpp
|
||||
layout/qgslayoutobject.cpp
|
||||
layout/qgslayoutpagecollection.cpp
|
||||
layout/qgslayoutserializableobject.cpp
|
||||
@ -1012,6 +1013,7 @@ SET(QGIS_CORE_HDRS
|
||||
layout/qgslayoutitemundocommand.h
|
||||
layout/qgslayoutmeasurement.h
|
||||
layout/qgslayoutmeasurementconverter.h
|
||||
layout/qgslayoutmultiframeundocommand.h
|
||||
layout/qgspagesizeregistry.h
|
||||
layout/qgslayoutpoint.h
|
||||
layout/qgslayoutserializableobject.h
|
||||
|
@ -207,6 +207,19 @@ QgsLayoutItem *QgsLayout::itemByUuid( const QString &uuid )
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QgsLayoutMultiFrame *QgsLayout::multiFrameByUuid( const QString &uuid ) const
|
||||
{
|
||||
for ( QgsLayoutMultiFrame *mf : mMultiFrames )
|
||||
{
|
||||
if ( mf->uuid() == uuid )
|
||||
{
|
||||
return mf;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
QgsLayoutItem *QgsLayout::layoutItemAt( QPointF position, const bool ignoreLocked ) const
|
||||
{
|
||||
return layoutItemAt( position, nullptr, ignoreLocked );
|
||||
@ -397,7 +410,8 @@ void QgsLayout::addLayoutItem( QgsLayoutItem *item )
|
||||
{
|
||||
undoText = tr( "Create Item" );
|
||||
}
|
||||
mUndoStack->stack()->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
|
||||
if ( mBlockUndoCommandCount == 0 )
|
||||
mUndoStack->stack()->push( new QgsLayoutItemAddItemCommand( item, undoText ) );
|
||||
}
|
||||
|
||||
void QgsLayout::removeLayoutItem( QgsLayoutItem *item )
|
||||
|
@ -208,9 +208,17 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
|
||||
/**
|
||||
* Returns the layout item with matching \a uuid unique identifier, or a nullptr
|
||||
* if a matching item could not be found.
|
||||
* \see multiFrameByUuid()
|
||||
*/
|
||||
QgsLayoutItem *itemByUuid( const QString &uuid );
|
||||
|
||||
/**
|
||||
* Returns the layout multiframe with matching \a uuid unique identifier, or a nullptr
|
||||
* if a matching multiframe could not be found.
|
||||
* \see itemByUuid()
|
||||
*/
|
||||
QgsLayoutMultiFrame *multiFrameByUuid( const QString &uuid ) const;
|
||||
|
||||
/**
|
||||
* Returns the topmost layout item at a specified \a position. Ignores paper items.
|
||||
* If \a ignoreLocked is set to true any locked items will be ignored.
|
||||
|
@ -41,11 +41,16 @@ QgsLayoutFrame::QgsLayoutFrame( QgsLayout *layout, QgsLayoutMultiFrame *multiFra
|
||||
}
|
||||
}
|
||||
|
||||
QgsLayoutFrame *QgsLayoutFrame::create( QgsLayout *layout )
|
||||
{
|
||||
return new QgsLayoutFrame( layout, nullptr );
|
||||
}
|
||||
|
||||
QgsLayoutMultiFrame *QgsLayoutFrame::multiFrame() const
|
||||
{
|
||||
return mMultiFrame;
|
||||
}
|
||||
#if 0// TODO
|
||||
#if 0// TODO - save/restore multiframe uuid!
|
||||
bool QgsLayoutFrame::writeXml( QDomElement &elem, QDomDocument &doc ) const
|
||||
{
|
||||
QDomElement frameElem = doc.createElement( QStringLiteral( "ComposerFrame" ) );
|
||||
|
@ -23,8 +23,6 @@
|
||||
class QgsLayout;
|
||||
class QgsLayoutMultiFrame;
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* Base class for frame items, which form a layout multiframe item.
|
||||
@ -42,6 +40,11 @@ class CORE_EXPORT QgsLayoutFrame: public QgsLayoutItem
|
||||
*/
|
||||
QgsLayoutFrame( QgsLayout *layout, QgsLayoutMultiFrame *multiFrame );
|
||||
|
||||
/**
|
||||
* Creates a new QgsLayoutFrame belonging to the specified \a layout.
|
||||
*/
|
||||
static QgsLayoutFrame *create( QgsLayout *layout ) SIP_FACTORY;
|
||||
|
||||
int type() const override;
|
||||
QString stringType() const override;
|
||||
|
||||
@ -134,6 +137,4 @@ class CORE_EXPORT QgsLayoutFrame: public QgsLayoutItem
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // QGSLAYOUTFRAME_H
|
||||
|
@ -90,6 +90,21 @@ QgsLayoutItemHtml::~QgsLayoutItemHtml()
|
||||
mFetcher->deleteLater();
|
||||
}
|
||||
|
||||
int QgsLayoutItemHtml::type() const
|
||||
{
|
||||
return QgsLayoutItemRegistry::LayoutHtml;
|
||||
}
|
||||
|
||||
QString QgsLayoutItemHtml::stringType() const
|
||||
{
|
||||
return QStringLiteral( "LayoutHtml" );
|
||||
}
|
||||
|
||||
QgsLayoutItemHtml *QgsLayoutItemHtml::create( QgsLayout *layout )
|
||||
{
|
||||
return new QgsLayoutItemHtml( layout );
|
||||
}
|
||||
|
||||
void QgsLayoutItemHtml::setUrl( const QUrl &url )
|
||||
{
|
||||
if ( !mWebPage )
|
||||
@ -449,9 +464,8 @@ QString QgsLayoutItemHtml::displayName() const
|
||||
return tr( "<HTML frame>" );
|
||||
}
|
||||
|
||||
bool QgsLayoutItemHtml::writeXml( QDomElement &elem, QDomDocument &doc, bool ignoreFrames ) const
|
||||
bool QgsLayoutItemHtml::writePropertiesToElement( QDomElement &htmlElem, QDomDocument &, const QgsReadWriteContext & ) const
|
||||
{
|
||||
QDomElement htmlElem = doc.createElement( QStringLiteral( "ComposerHtml" ) );
|
||||
htmlElem.setAttribute( QStringLiteral( "contentMode" ), QString::number( static_cast< int >( mContentMode ) ) );
|
||||
htmlElem.setAttribute( QStringLiteral( "url" ), mUrl.toString() );
|
||||
htmlElem.setAttribute( QStringLiteral( "html" ), mHtml );
|
||||
@ -460,25 +474,11 @@ bool QgsLayoutItemHtml::writeXml( QDomElement &elem, QDomDocument &doc, bool ign
|
||||
htmlElem.setAttribute( QStringLiteral( "maxBreakDistance" ), QString::number( mMaxBreakDistance ) );
|
||||
htmlElem.setAttribute( QStringLiteral( "stylesheet" ), mUserStylesheet );
|
||||
htmlElem.setAttribute( QStringLiteral( "stylesheetEnabled" ), mEnableUserStylesheet ? "true" : "false" );
|
||||
|
||||
bool state = _writeXml( htmlElem, doc, ignoreFrames );
|
||||
elem.appendChild( htmlElem );
|
||||
return state;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsLayoutItemHtml::readXml( const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames )
|
||||
bool QgsLayoutItemHtml::readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &, const QgsReadWriteContext & )
|
||||
{
|
||||
if ( !ignoreFrames )
|
||||
{
|
||||
deleteFrames();
|
||||
}
|
||||
|
||||
//first create the frames
|
||||
if ( !_readXml( itemElem, doc, ignoreFrames ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool contentModeOK;
|
||||
mContentMode = static_cast< QgsLayoutItemHtml::ContentMode >( itemElem.attribute( QStringLiteral( "contentMode" ) ).toInt( &contentModeOK ) );
|
||||
if ( !contentModeOK )
|
||||
|
@ -55,6 +55,14 @@ class CORE_EXPORT QgsLayoutItemHtml: public QgsLayoutMultiFrame
|
||||
|
||||
~QgsLayoutItemHtml();
|
||||
|
||||
int type() const override;
|
||||
QString stringType() const override;
|
||||
|
||||
/**
|
||||
* Returns a new QgsLayoutItemHtml for the specified parent \a layout.
|
||||
*/
|
||||
static QgsLayoutItemHtml *create( QgsLayout *layout ) SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Sets the source \a mode for item's HTML content.
|
||||
* \see contentMode()
|
||||
@ -199,8 +207,6 @@ class CORE_EXPORT QgsLayoutItemHtml: public QgsLayoutMultiFrame
|
||||
void render( QgsRenderContext &context, const QRectF &renderExtent, const int frameIndex,
|
||||
const QStyleOptionGraphicsItem *itemStyle = nullptr ) override;
|
||||
|
||||
bool writeXml( QDomElement &elem, QDomDocument &doc, bool ignoreFrames = false ) const override;
|
||||
bool readXml( const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames = false ) override;
|
||||
//overridden to break frames without dividing lines of text
|
||||
double findNearbyPageBreak( double yPos ) override;
|
||||
|
||||
@ -222,6 +228,11 @@ class CORE_EXPORT QgsLayoutItemHtml: public QgsLayoutMultiFrame
|
||||
|
||||
void refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property = QgsLayoutObject::AllProperties );
|
||||
|
||||
protected:
|
||||
|
||||
bool writePropertiesToElement( QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context ) const override;
|
||||
bool readPropertiesFromElement( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context ) override;
|
||||
|
||||
private slots:
|
||||
void frameLoaded( bool ok = true );
|
||||
|
||||
|
@ -24,6 +24,8 @@
|
||||
#include "qgslayoutitempage.h"
|
||||
#include "qgslayoutitempicture.h"
|
||||
#include "qgslayoutitemgroup.h"
|
||||
#include "qgslayoutitemhtml.h"
|
||||
#include "qgslayoutframe.h"
|
||||
#include "qgsgloweffect.h"
|
||||
#include "qgseffectstack.h"
|
||||
#include <QPainter>
|
||||
@ -51,6 +53,7 @@ bool QgsLayoutItemRegistry::populate()
|
||||
|
||||
addLayoutItemType( new QgsLayoutItemMetadata( QgsLayoutItemRegistry::LayoutItem + 1002, QStringLiteral( "temp type" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLabel.svg" ) ), createTemporaryItem ) );
|
||||
addLayoutItemType( new QgsLayoutItemMetadata( LayoutGroup, QStringLiteral( "Group" ), QIcon(), QgsLayoutItemGroup::create ) );
|
||||
addLayoutItemType( new QgsLayoutItemMetadata( LayoutFrame, QStringLiteral( "Frame" ), QIcon(), QgsLayoutFrame::create ) );
|
||||
addLayoutItemType( new QgsLayoutItemMetadata( LayoutPage, QStringLiteral( "Page" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileNew.svg" ) ), QgsLayoutItemPage::create ) );
|
||||
addLayoutItemType( new QgsLayoutItemMetadata( LayoutMap, QStringLiteral( "Map" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddMap.svg" ) ), QgsLayoutItemMap::create ) );
|
||||
addLayoutItemType( new QgsLayoutItemMetadata( LayoutPicture, QStringLiteral( "Picture" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddImage.svg" ) ), QgsLayoutItemPicture::create ) );
|
||||
@ -65,6 +68,8 @@ bool QgsLayoutItemRegistry::populate()
|
||||
addLayoutItemType( new QgsLayoutItemMetadata( LayoutPolygon, QStringLiteral( "Polygon" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolygon.svg" ) ), QgsLayoutItemPolygon::create ) );
|
||||
addLayoutItemType( new QgsLayoutItemMetadata( LayoutPolyline, QStringLiteral( "Polyline" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolyline.svg" ) ), QgsLayoutItemPolyline::create ) );
|
||||
|
||||
addLayoutMultiFrameType( new QgsLayoutMultiFrameMetadata( LayoutHtml, QStringLiteral( "HTML" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddHtml.svg" ) ), QgsLayoutItemHtml::create ) );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -73,6 +78,11 @@ QgsLayoutItemAbstractMetadata *QgsLayoutItemRegistry::itemMetadata( int type ) c
|
||||
return mMetadata.value( type );
|
||||
}
|
||||
|
||||
QgsLayoutMultiFrameAbstractMetadata *QgsLayoutItemRegistry::multiFrameMetadata( int type ) const
|
||||
{
|
||||
return mMultiFrameMetadata.value( type );
|
||||
}
|
||||
|
||||
bool QgsLayoutItemRegistry::addLayoutItemType( QgsLayoutItemAbstractMetadata *metadata )
|
||||
{
|
||||
if ( !metadata || mMetadata.contains( metadata->type() ) )
|
||||
@ -83,6 +93,16 @@ bool QgsLayoutItemRegistry::addLayoutItemType( QgsLayoutItemAbstractMetadata *me
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsLayoutItemRegistry::addLayoutMultiFrameType( QgsLayoutMultiFrameAbstractMetadata *metadata )
|
||||
{
|
||||
if ( !metadata || mMultiFrameMetadata.contains( metadata->type() ) )
|
||||
return false;
|
||||
|
||||
mMultiFrameMetadata[metadata->type()] = metadata;
|
||||
emit multiFrameTypeAdded( metadata->type(), metadata->visibleName() );
|
||||
return true;
|
||||
}
|
||||
|
||||
QgsLayoutItem *QgsLayoutItemRegistry::createItem( int type, QgsLayout *layout ) const
|
||||
{
|
||||
if ( !mMetadata.contains( type ) )
|
||||
@ -91,23 +111,38 @@ QgsLayoutItem *QgsLayoutItemRegistry::createItem( int type, QgsLayout *layout )
|
||||
return mMetadata[type]->createItem( layout );
|
||||
}
|
||||
|
||||
QgsLayoutMultiFrame *QgsLayoutItemRegistry::createMultiFrame( int type, QgsLayout *layout ) const
|
||||
{
|
||||
if ( !mMultiFrameMetadata.contains( type ) )
|
||||
return nullptr;
|
||||
|
||||
return mMultiFrameMetadata[type]->createMultiFrame( layout );
|
||||
}
|
||||
|
||||
void QgsLayoutItemRegistry::resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const
|
||||
{
|
||||
if ( !mMetadata.contains( type ) )
|
||||
return;
|
||||
|
||||
mMetadata[type]->resolvePaths( properties, pathResolver, saving );
|
||||
|
||||
if ( mMetadata.contains( type ) )
|
||||
{
|
||||
mMetadata[type]->resolvePaths( properties, pathResolver, saving );
|
||||
}
|
||||
else if ( mMultiFrameMetadata.contains( type ) )
|
||||
{
|
||||
mMultiFrameMetadata[type]->resolvePaths( properties, pathResolver, saving );
|
||||
}
|
||||
}
|
||||
|
||||
QMap<int, QString> QgsLayoutItemRegistry::itemTypes() const
|
||||
{
|
||||
QMap<int, QString> types;
|
||||
QMap<int, QgsLayoutItemAbstractMetadata *>::ConstIterator it = mMetadata.constBegin();
|
||||
for ( ; it != mMetadata.constEnd(); ++it )
|
||||
for ( auto it = mMetadata.constBegin(); it != mMetadata.constEnd(); ++it )
|
||||
{
|
||||
types.insert( it.key(), it.value()->visibleName() );
|
||||
}
|
||||
for ( auto it = mMultiFrameMetadata.constBegin(); it != mMultiFrameMetadata.constEnd(); ++it )
|
||||
{
|
||||
types.insert( it.key(), it.value()->visibleName() );
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ class QgsLayout;
|
||||
class QgsLayoutView;
|
||||
class QgsLayoutItem;
|
||||
class QgsFillSymbol;
|
||||
class QgsLayoutMultiFrame;
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
@ -155,6 +156,129 @@ class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* \brief Stores metadata about one layout multiframe class.
|
||||
*
|
||||
* A companion class, QgsLayoutMultiFrameAbstractGuiMetadata, handles the
|
||||
* GUI behavior of QgsLayoutMultiFrames.
|
||||
*
|
||||
* \note In C++ you can use QgsLayoutMultiFrameMetadata convenience class.
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsLayoutMultiFrameAbstractMetadata
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsLayoutMultiFrameAbstractMetadata with the specified class \a type
|
||||
* and \a visibleName.
|
||||
*/
|
||||
QgsLayoutMultiFrameAbstractMetadata( int type, const QString &visibleName )
|
||||
: mType( type )
|
||||
, mVisibleName( visibleName )
|
||||
{}
|
||||
|
||||
virtual ~QgsLayoutMultiFrameAbstractMetadata() = default;
|
||||
|
||||
/**
|
||||
* Returns the unique item type code for the layout multiframe class.
|
||||
*/
|
||||
int type() const { return mType; }
|
||||
|
||||
/**
|
||||
* Returns an icon representing the layout multiframe type.
|
||||
*/
|
||||
virtual QIcon icon() const { return QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ); }
|
||||
|
||||
/**
|
||||
* Returns a translated, user visible name for the layout multiframe class.
|
||||
*/
|
||||
QString visibleName() const { return mVisibleName; }
|
||||
|
||||
/**
|
||||
* Creates a layout multiframe of this class for a specified \a layout.
|
||||
*/
|
||||
virtual QgsLayoutMultiFrame *createMultiFrame( QgsLayout *layout ) = 0 SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Resolve paths in the item's \a properties (if there are any paths).
|
||||
* When \a saving is true, paths are converted from absolute to relative,
|
||||
* when \a saving is false, paths are converted from relative to absolute.
|
||||
* This ensures that paths in project files can be relative, but in item
|
||||
* instances the paths are always absolute.
|
||||
*/
|
||||
virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving )
|
||||
{
|
||||
Q_UNUSED( properties );
|
||||
Q_UNUSED( pathResolver );
|
||||
Q_UNUSED( saving );
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
int mType = -1;
|
||||
QString mVisibleName;
|
||||
};
|
||||
|
||||
//! Layout multiframe creation function
|
||||
typedef std::function<QgsLayoutMultiFrame *( QgsLayout * )> QgsLayoutMultiFrameCreateFunc SIP_SKIP;
|
||||
|
||||
//! Layout multiframe path resolver function
|
||||
typedef std::function<void( QVariantMap &, const QgsPathResolver &, bool )> QgsLayoutMultiFramePathResolverFunc SIP_SKIP;
|
||||
|
||||
#ifndef SIP_RUN
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* Convenience metadata class that uses static functions to create layout multiframes and their configuration widgets.
|
||||
* \since QGIS 3.0
|
||||
* \note not available in Python bindings
|
||||
*/
|
||||
class CORE_EXPORT QgsLayoutMultiFrameMetadata : public QgsLayoutMultiFrameAbstractMetadata
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsLayoutMultiFrameMetadata with the specified class \a type
|
||||
* and \a visibleName, and function pointers for the various item creation functions.
|
||||
*/
|
||||
QgsLayoutMultiFrameMetadata( int type, const QString &visibleName, const QIcon &icon,
|
||||
QgsLayoutMultiFrameCreateFunc pfCreate,
|
||||
QgsLayoutMultiFramePathResolverFunc pfPathResolver = nullptr )
|
||||
: QgsLayoutMultiFrameAbstractMetadata( type, visibleName )
|
||||
, mIcon( icon )
|
||||
, mCreateFunc( pfCreate )
|
||||
, mPathResolverFunc( pfPathResolver )
|
||||
{}
|
||||
|
||||
/**
|
||||
* Returns the classes' multiframe creation function.
|
||||
*/
|
||||
QgsLayoutMultiFrameCreateFunc createFunction() const { return mCreateFunc; }
|
||||
|
||||
/**
|
||||
* Returns the classes' path resolver function.
|
||||
*/
|
||||
QgsLayoutMultiFramePathResolverFunc pathResolverFunction() const { return mPathResolverFunc; }
|
||||
|
||||
QIcon icon() const override { return mIcon.isNull() ? QgsLayoutMultiFrameAbstractMetadata::icon() : mIcon; }
|
||||
QgsLayoutMultiFrame *createMultiFrame( QgsLayout *layout ) override { return mCreateFunc ? mCreateFunc( layout ) : nullptr; }
|
||||
|
||||
void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) override
|
||||
{
|
||||
if ( mPathResolverFunc )
|
||||
mPathResolverFunc( properties, pathResolver, saving );
|
||||
}
|
||||
|
||||
protected:
|
||||
QIcon mIcon;
|
||||
QgsLayoutMultiFrameCreateFunc mCreateFunc = nullptr;
|
||||
QgsLayoutMultiFramePathResolverFunc mPathResolverFunc = nullptr;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
@ -193,6 +317,9 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
|
||||
LayoutPolyline, //!< Polyline shape item
|
||||
LayoutFrame, //!< Frame item, part of a QgsLayoutMultiFrame object
|
||||
|
||||
// known multi-frame types
|
||||
LayoutHtml, //!< Html multiframe item
|
||||
|
||||
// item types provided by plugins
|
||||
PluginItem, //!< Starting point for plugin item types
|
||||
};
|
||||
@ -223,19 +350,41 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
|
||||
/**
|
||||
* Returns the metadata for the specified item \a type. Returns nullptr if
|
||||
* a corresponding type was not found in the registry.
|
||||
* \see multiFrameMetadata()
|
||||
*/
|
||||
QgsLayoutItemAbstractMetadata *itemMetadata( int type ) const;
|
||||
|
||||
/**
|
||||
* Returns the metadata for the specified multiframe \a type. Returns nullptr if
|
||||
* a corresponding type was not found in the registry.
|
||||
* \see itemMetadata()
|
||||
*/
|
||||
QgsLayoutMultiFrameAbstractMetadata *multiFrameMetadata( int type ) const;
|
||||
|
||||
/**
|
||||
* Registers a new layout item type. Takes ownership of the metadata instance.
|
||||
* \see addLayoutMultiFrameType()
|
||||
*/
|
||||
bool addLayoutItemType( QgsLayoutItemAbstractMetadata *metadata SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Registers a new layout multiframe type. Takes ownership of the metadata instance.
|
||||
* \see addLayoutItemType()
|
||||
*/
|
||||
bool addLayoutMultiFrameType( QgsLayoutMultiFrameAbstractMetadata *metadata SIP_TRANSFER );
|
||||
|
||||
/**
|
||||
* Creates a new instance of a layout item given the item \a type, and target \a layout.
|
||||
* \see createMultiFrame()
|
||||
*/
|
||||
QgsLayoutItem *createItem( int type, QgsLayout *layout ) const SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Creates a new instance of a layout multiframe given the multiframe \a type, and target \a layout.
|
||||
* \see createItem()
|
||||
*/
|
||||
QgsLayoutMultiFrame *createMultiFrame( int type, QgsLayout *layout ) const SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Resolve paths in properties of a particular symbol layer.
|
||||
* This normally means converting relative paths to absolute paths when loading
|
||||
@ -256,12 +405,19 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
|
||||
*/
|
||||
void typeAdded( int type, const QString &name );
|
||||
|
||||
/**
|
||||
* Emitted whenever a new multiframe type is added to the registry, with the specified
|
||||
* \a type and visible \a name.
|
||||
*/
|
||||
void multiFrameTypeAdded( int type, const QString &name );
|
||||
|
||||
private:
|
||||
#ifdef SIP_RUN
|
||||
QgsLayoutItemRegistry( const QgsLayoutItemRegistry &rh );
|
||||
#endif
|
||||
|
||||
QMap<int, QgsLayoutItemAbstractMetadata *> mMetadata;
|
||||
QMap<int, QgsLayoutMultiFrameAbstractMetadata *> mMultiFrameMetadata;
|
||||
|
||||
};
|
||||
|
||||
|
@ -14,12 +14,14 @@
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgslayoutmultiframe.h"
|
||||
#include "qgslayoutmultiframeundocommand.h"
|
||||
#include "qgslayoutframe.h"
|
||||
#include "qgslayout.h"
|
||||
#include <QtCore>
|
||||
|
||||
QgsLayoutMultiFrame::QgsLayoutMultiFrame( QgsLayout *layout )
|
||||
: QgsLayoutObject( layout )
|
||||
, mUuid( QUuid::createUuid().toString() )
|
||||
{
|
||||
mLayout->addMultiFrame( this );
|
||||
|
||||
@ -98,6 +100,9 @@ void QgsLayoutMultiFrame::recalculateFrameSizes()
|
||||
return;
|
||||
}
|
||||
|
||||
if ( mBlockUndoCommands )
|
||||
mLayout->mBlockUndoCommandCount++;
|
||||
|
||||
double currentY = 0;
|
||||
double currentHeight = 0;
|
||||
QgsLayoutFrame *currentItem = nullptr;
|
||||
@ -206,6 +211,9 @@ void QgsLayoutMultiFrame::recalculateFrameSizes()
|
||||
currentItem = newFrame;
|
||||
}
|
||||
}
|
||||
|
||||
if ( mBlockUndoCommands )
|
||||
mLayout->mBlockUndoCommandCount--;
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrame::recalculateFrameRects()
|
||||
@ -257,6 +265,31 @@ QString QgsLayoutMultiFrame::displayName() const
|
||||
return tr( "<Multiframe>" );
|
||||
}
|
||||
|
||||
QgsAbstractLayoutUndoCommand *QgsLayoutMultiFrame::createCommand( const QString &text, int id, QUndoCommand *parent )
|
||||
{
|
||||
return new QgsLayoutMultiFrameUndoCommand( this, text, id, parent );
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrame::beginCommand( const QString &commandText, QgsLayoutMultiFrame::UndoCommand command )
|
||||
{
|
||||
if ( !mLayout )
|
||||
return;
|
||||
|
||||
mLayout->undoStack()->beginCommand( this, commandText, command );
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrame::endCommand()
|
||||
{
|
||||
if ( mLayout )
|
||||
mLayout->undoStack()->endCommand();
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrame::cancelCommand()
|
||||
{
|
||||
if ( mLayout )
|
||||
mLayout->undoStack()->cancelCommand();
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrame::handleFrameRemoval()
|
||||
{
|
||||
if ( mBlockUpdates )
|
||||
@ -394,10 +427,15 @@ int QgsLayoutMultiFrame::frameIndex( QgsLayoutFrame *frame ) const
|
||||
return mFrameItems.indexOf( frame );
|
||||
}
|
||||
|
||||
bool QgsLayoutMultiFrame::_writeXml( QDomElement &elem, QDomDocument &doc, bool ignoreFrames ) const
|
||||
bool QgsLayoutMultiFrame::writeXml( QDomElement &parentElement, QDomDocument &doc, const QgsReadWriteContext &context, bool ignoreFrames ) const
|
||||
{
|
||||
QDomElement element = doc.createElement( QStringLiteral( "LayoutMultiFrame" ) );
|
||||
element.setAttribute( QStringLiteral( "resizeMode" ), mResizeMode );
|
||||
element.setAttribute( QStringLiteral( "uuid" ), mUuid );
|
||||
element.setAttribute( QStringLiteral( "type" ), stringType() );
|
||||
|
||||
#if 0 //TODO
|
||||
elem.setAttribute( QStringLiteral( "resizeMode" ), mResizeMode );
|
||||
|
||||
if ( !ignoreFrames )
|
||||
{
|
||||
QList<QgsComposerFrame *>::const_iterator frameIt = mFrameItems.constBegin();
|
||||
@ -406,17 +444,34 @@ bool QgsLayoutMultiFrame::_writeXml( QDomElement &elem, QDomDocument &doc, bool
|
||||
( *frameIt )->writeXml( elem, doc );
|
||||
}
|
||||
}
|
||||
QgsComposerObject::writeXml( elem, doc );
|
||||
#endif
|
||||
|
||||
writeObjectPropertiesToElement( element, doc, context );
|
||||
writePropertiesToElement( element, doc, context );
|
||||
parentElement.appendChild( element );
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsLayoutMultiFrame::_readXml( const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames )
|
||||
bool QgsLayoutMultiFrame::readXml( const QDomElement &element, const QDomDocument &doc, const QgsReadWriteContext &context, bool ignoreFrames )
|
||||
{
|
||||
#if 0 //TODO
|
||||
QgsComposerObject::readXml( itemElem, doc );
|
||||
if ( element.nodeName() != QStringLiteral( "LayoutMultiFrame" ) || element.attribute( QStringLiteral( "type" ) ) != stringType() )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
mBlockUndoCommands = true;
|
||||
|
||||
readObjectPropertiesFromElement( element, doc, context );
|
||||
|
||||
mUuid = element.attribute( QStringLiteral( "uuid" ), QUuid::createUuid().toString() );
|
||||
mResizeMode = static_cast< ResizeMode >( element.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() );
|
||||
#if 0 //TODO
|
||||
if ( !ignoreFrames )
|
||||
{
|
||||
deleteFrames();
|
||||
}
|
||||
|
||||
|
||||
mResizeMode = static_cast< ResizeMode >( itemElem.attribute( QStringLiteral( "resizeMode" ), QStringLiteral( "0" ) ).toInt() );
|
||||
if ( !ignoreFrames )
|
||||
{
|
||||
QDomNodeList frameList = itemElem.elementsByTagName( QStringLiteral( "ComposerFrame" ) );
|
||||
@ -431,7 +486,22 @@ bool QgsLayoutMultiFrame::_readXml( const QDomElement &itemElem, const QDomDocum
|
||||
//TODO - think there should be a recalculateFrameSizes() call here
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool result = readPropertiesFromElement( element, doc, context );
|
||||
|
||||
mBlockUndoCommands = false;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool QgsLayoutMultiFrame::writePropertiesToElement( QDomElement &, QDomDocument &, const QgsReadWriteContext & ) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsLayoutMultiFrame::readPropertiesFromElement( const QDomElement &, const QDomDocument &, const QgsReadWriteContext & )
|
||||
{
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "qgis_core.h"
|
||||
#include "qgis.h"
|
||||
#include "qgslayoutobject.h"
|
||||
#include "qgslayoutundocommand.h"
|
||||
#include <QObject>
|
||||
#include <QSizeF>
|
||||
#include <QPointF>
|
||||
@ -41,10 +42,7 @@ class QgsRenderContext;
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
|
||||
// sip crashes out on this file - reexamine after composer removal
|
||||
#ifndef SIP_RUN
|
||||
|
||||
class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject
|
||||
class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject, public QgsLayoutUndoObjectInterface
|
||||
{
|
||||
|
||||
Q_OBJECT
|
||||
@ -63,6 +61,12 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject
|
||||
until the entire multiframe content is visible */
|
||||
};
|
||||
|
||||
//! Multiframe item undo commands, used for collapsing undo commands
|
||||
enum UndoCommand
|
||||
{
|
||||
UndoNone = -1, //!< No command suppression
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a new multiframe item, attached to the specified \a layout.
|
||||
*/
|
||||
@ -70,11 +74,31 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject
|
||||
|
||||
~QgsLayoutMultiFrame();
|
||||
|
||||
/**
|
||||
* Returns the multiframe identification string. This is a unique random string set for the multiframe
|
||||
* upon creation.
|
||||
* \note There is no corresponding setter for the uuid - it's created automatically.
|
||||
*/
|
||||
QString uuid() const { return mUuid; }
|
||||
|
||||
/**
|
||||
* Returns the total size of the multiframe's content, in layout units.
|
||||
*/
|
||||
virtual QSizeF totalSize() const = 0;
|
||||
|
||||
/**
|
||||
* Returns unique multiframe type id.
|
||||
*/
|
||||
virtual int type() const = 0;
|
||||
|
||||
/**
|
||||
* Return the multiframe type as a string.
|
||||
*
|
||||
* This string must be a unique, single word, character only representation of the item type, eg "LayoutHtml"
|
||||
* \see type()
|
||||
*/
|
||||
virtual QString stringType() const = 0;
|
||||
|
||||
/**
|
||||
* Returns the fixed size for a frame, if desired. If the fixed frame size changes,
|
||||
* the sizes of all frames can be recalculated by calling recalculateFrameRects().
|
||||
@ -157,51 +181,30 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject
|
||||
ResizeMode resizeMode() const { return mResizeMode; }
|
||||
|
||||
/**
|
||||
* Stores state information about multiframe in DOM element. Implementations of writeXml
|
||||
* should also call the _writeXML method to save general multiframe properties.
|
||||
* \param elem is DOM element
|
||||
* \param doc is the DOM document
|
||||
* Stores the multiframe state in a DOM element.
|
||||
* \param parentElement parent DOM element (e.g. 'Layout' element)
|
||||
* \param document DOM document
|
||||
* \param context read write context
|
||||
* \param ignoreFrames set to false to avoid writing state information about child frames into DOM
|
||||
* \see _writeXML
|
||||
* \see readXml()
|
||||
*/
|
||||
virtual bool writeXml( QDomElement &elem, QDomDocument &doc, bool ignoreFrames = false ) const = 0;
|
||||
bool writeXml( QDomElement &elem, QDomDocument &doc, const QgsReadWriteContext &context, bool ignoreFrames = false ) const;
|
||||
|
||||
/**
|
||||
* Stores state information about base multiframe object in DOM element. Implementations of writeXml
|
||||
* should call this method.
|
||||
* \param elem is DOM element
|
||||
* \param doc is the DOM document
|
||||
* \param ignoreFrames set to false to avoid writing state information about child frames into DOM
|
||||
* \see writeXml
|
||||
*/
|
||||
bool _writeXml( QDomElement &elem, QDomDocument &doc, bool ignoreFrames = false ) const;
|
||||
|
||||
/**
|
||||
* Reads multiframe state information from a DOM element. Implementations of readXml
|
||||
* should also call the _readXML method to restore general multiframe properties.
|
||||
* \param itemElem is DOM element
|
||||
* \param doc is the DOM document
|
||||
* Sets the item state from a DOM element.
|
||||
* \param itemElement is the DOM node corresponding to item (e.g. 'LayoutItem' element)
|
||||
* \param document DOM document
|
||||
* \param context read write context
|
||||
* \param ignoreFrames set to false to avoid read state information about child frames from DOM
|
||||
* \see _readXML
|
||||
* \see writeXml()
|
||||
*/
|
||||
virtual bool readXml( const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames = false ) = 0;
|
||||
|
||||
/**
|
||||
* Restores state information about base multiframe object from a DOM element. Implementations of readXml
|
||||
* should call this method.
|
||||
* \param itemElem is DOM element
|
||||
* \param doc is the DOM document
|
||||
* \param ignoreFrames set to false to avoid reading state information about child frames from DOM
|
||||
* \see readXml
|
||||
*/
|
||||
bool _readXml( const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames = false );
|
||||
bool readXml( const QDomElement &itemElem, const QDomDocument &doc, const QgsReadWriteContext &context, bool ignoreFrames = false );
|
||||
|
||||
/**
|
||||
* Returns a list of all child frames for this multiframe.
|
||||
* \see frameCount()
|
||||
* \note Not available in Python bindings
|
||||
*/
|
||||
QList<QgsLayoutFrame *> frames() const SIP_SKIP;
|
||||
QList<QgsLayoutFrame *> frames() const;
|
||||
|
||||
/**
|
||||
* Returns the number of frames associated with this multiframe.
|
||||
@ -236,6 +239,32 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject
|
||||
*/
|
||||
virtual QString displayName() const;
|
||||
|
||||
QgsAbstractLayoutUndoCommand *createCommand( const QString &text, int id, QUndoCommand *parent = nullptr ) override SIP_FACTORY;
|
||||
|
||||
/**
|
||||
* Starts new undo command for this item.
|
||||
* The \a commandText should be a capitalized, imperative tense description (e.g. "Add Map Item").
|
||||
* If specified, multiple consecutive commands for this item with the same \a command will
|
||||
* be collapsed into a single undo command in the layout history.
|
||||
* \see endCommand()
|
||||
* \see cancelCommand()
|
||||
*/
|
||||
void beginCommand( const QString &commandText, UndoCommand command = UndoNone );
|
||||
|
||||
/**
|
||||
* Completes the current item command and push it onto the layout's undo stack.
|
||||
* \see beginCommand()
|
||||
* \see cancelCommand()
|
||||
*/
|
||||
void endCommand();
|
||||
|
||||
/**
|
||||
* Cancels the current item command and discards it.
|
||||
* \see beginCommand()
|
||||
* \see endCommand()
|
||||
*/
|
||||
void cancelCommand();
|
||||
|
||||
public slots:
|
||||
|
||||
/**
|
||||
@ -278,6 +307,26 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Stores multiframe state within an XML DOM element.
|
||||
* \param element is the DOM element to store the multiframe's properties in
|
||||
* \param document DOM document
|
||||
* \param context read write context
|
||||
* \see writeXml()
|
||||
* \see readPropertiesFromElement()
|
||||
*/
|
||||
virtual bool writePropertiesToElement( QDomElement &element, QDomDocument &document, const QgsReadWriteContext &context ) const;
|
||||
|
||||
/**
|
||||
* Sets multiframe state from a DOM element.
|
||||
* \param element is the DOM element for the multiframe
|
||||
* \param document DOM document
|
||||
* \param context read write context
|
||||
* \see writePropertiesToElement()
|
||||
* \see readXml()
|
||||
*/
|
||||
virtual bool readPropertiesFromElement( const QDomElement &element, const QDomDocument &document, const QgsReadWriteContext &context );
|
||||
|
||||
QList<QgsLayoutFrame *> mFrameItems;
|
||||
|
||||
ResizeMode mResizeMode = UseExistingFrames;
|
||||
@ -302,8 +351,11 @@ class CORE_EXPORT QgsLayoutMultiFrame: public QgsLayoutObject
|
||||
bool mIsRecalculatingSize = false;
|
||||
|
||||
bool mBlockUpdates = false;
|
||||
bool mBlockUndoCommands = false;
|
||||
|
||||
//! Unique id
|
||||
QString mUuid;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif // QGSLAYOUTMULTIFRAME_H
|
||||
|
161
src/core/layout/qgslayoutmultiframeundocommand.cpp
Normal file
161
src/core/layout/qgslayoutmultiframeundocommand.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
/***************************************************************************
|
||||
qgslayoutmultiframeundocommand.cpp
|
||||
----------------------
|
||||
begin : October 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#include "qgslayoutmultiframeundocommand.h"
|
||||
#include "qgslayoutmultiframe.h"
|
||||
#include "qgsreadwritecontext.h"
|
||||
#include "qgslayout.h"
|
||||
#include "qgsproject.h"
|
||||
|
||||
///@cond PRIVATE
|
||||
QgsLayoutMultiFrameUndoCommand::QgsLayoutMultiFrameUndoCommand( QgsLayoutMultiFrame *frame, const QString &text, int id, QUndoCommand *parent )
|
||||
: QgsAbstractLayoutUndoCommand( text, id, parent )
|
||||
, mFrameUuid( frame->uuid() )
|
||||
, mLayout( frame->layout() )
|
||||
, mItemType( frame->type() )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool QgsLayoutMultiFrameUndoCommand::mergeWith( const QUndoCommand *command )
|
||||
{
|
||||
if ( command->id() == 0 )
|
||||
return false;
|
||||
|
||||
const QgsLayoutMultiFrameUndoCommand *c = dynamic_cast<const QgsLayoutMultiFrameUndoCommand *>( command );
|
||||
if ( !c )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if ( c->multiFrameUuid() != multiFrameUuid() )
|
||||
return false;
|
||||
|
||||
setAfterState( c->afterState() );
|
||||
return true;
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrameUndoCommand::saveState( QDomDocument &stateDoc ) const
|
||||
{
|
||||
stateDoc.clear();
|
||||
QDomElement documentElement = stateDoc.createElement( QStringLiteral( "ItemState" ) );
|
||||
|
||||
QgsLayoutMultiFrame *item = mLayout->multiFrameByUuid( mFrameUuid );
|
||||
Q_ASSERT_X( item, "QgsLayoutMultiFrameUndoCommand::saveState", "could not retrieve item for saving state" );
|
||||
|
||||
item->writeXml( documentElement, stateDoc, QgsReadWriteContext() );
|
||||
stateDoc.appendChild( documentElement );
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrameUndoCommand::restoreState( QDomDocument &stateDoc )
|
||||
{
|
||||
// find item by uuid...
|
||||
QgsLayoutMultiFrame *item = mLayout->multiFrameByUuid( mFrameUuid );
|
||||
if ( !item )
|
||||
{
|
||||
// uh oh - it's been deleted! we need to create a new instance
|
||||
item = recreateItem( mItemType, mLayout );
|
||||
}
|
||||
|
||||
item->readXml( stateDoc.documentElement().firstChild().toElement(), stateDoc, QgsReadWriteContext() );
|
||||
mLayout->project()->setDirty( true );
|
||||
}
|
||||
|
||||
QgsLayoutMultiFrame *QgsLayoutMultiFrameUndoCommand::recreateItem( int itemType, QgsLayout *layout )
|
||||
{
|
||||
QgsLayoutMultiFrame *item = QgsApplication::layoutItemRegistry()->createMultiFrame( itemType, layout );
|
||||
mLayout->addMultiFrame( item );
|
||||
return item;
|
||||
}
|
||||
|
||||
QString QgsLayoutMultiFrameUndoCommand::multiFrameUuid() const
|
||||
{
|
||||
return mFrameUuid;
|
||||
}
|
||||
|
||||
QgsLayout *QgsLayoutMultiFrameUndoCommand::layout() const
|
||||
{
|
||||
return mLayout;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// QgsLayoutMultiFrameDeleteUndoCommand
|
||||
//
|
||||
|
||||
QgsLayoutMultiFrameDeleteUndoCommand::QgsLayoutMultiFrameDeleteUndoCommand( QgsLayoutMultiFrame *item, const QString &text, int id, QUndoCommand *parent )
|
||||
: QgsLayoutMultiFrameUndoCommand( item, text, id, parent )
|
||||
{
|
||||
saveBeforeState();
|
||||
}
|
||||
|
||||
bool QgsLayoutMultiFrameDeleteUndoCommand::mergeWith( const QUndoCommand * )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrameDeleteUndoCommand::redo()
|
||||
{
|
||||
if ( mFirstRun )
|
||||
{
|
||||
mFirstRun = false;
|
||||
return;
|
||||
}
|
||||
|
||||
QgsLayoutMultiFrame *item = layout()->multiFrameByUuid( multiFrameUuid() );
|
||||
//Q_ASSERT_X( item, "QgsLayoutMultiFrameDeleteUndoCommand::redo", "could not find item to re-delete!" );
|
||||
|
||||
if ( item )
|
||||
{
|
||||
layout()->removeMultiFrame( item );
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
QgsLayoutMultiFrameAddItemCommand::QgsLayoutMultiFrameAddItemCommand( QgsLayoutMultiFrame *frame, const QString &text, int id, QUndoCommand *parent )
|
||||
: QgsLayoutMultiFrameUndoCommand( frame, text, id, parent )
|
||||
{
|
||||
saveAfterState();
|
||||
}
|
||||
|
||||
bool QgsLayoutMultiFrameAddItemCommand::containsChange() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool QgsLayoutMultiFrameAddItemCommand::mergeWith( const QUndoCommand * )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void QgsLayoutMultiFrameAddItemCommand::undo()
|
||||
{
|
||||
if ( mFirstRun )
|
||||
{
|
||||
mFirstRun = false;
|
||||
return;
|
||||
}
|
||||
|
||||
QgsLayoutMultiFrame *item = layout()->multiFrameByUuid( multiFrameUuid() );
|
||||
if ( item )
|
||||
{
|
||||
layout()->removeMultiFrame( item );
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///@endcond
|
141
src/core/layout/qgslayoutmultiframeundocommand.h
Normal file
141
src/core/layout/qgslayoutmultiframeundocommand.h
Normal file
@ -0,0 +1,141 @@
|
||||
/***************************************************************************
|
||||
qgslayoutmultiframeundocommand.h
|
||||
----------------------
|
||||
begin : October 2017
|
||||
copyright : (C) 2017 by Nyall Dawson
|
||||
email : nyall dot dawson at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef QGSLAYOUTMULTIFRAMEUNDOCOMMAND_H
|
||||
#define QGSLAYOUTMULTIFRAMEUNDOCOMMAND_H
|
||||
|
||||
#include "qgslayoutundocommand.h"
|
||||
#include "qgis_core.h"
|
||||
|
||||
class QgsLayout;
|
||||
class QgsLayoutMultiFrame;
|
||||
|
||||
SIP_NO_FILE
|
||||
|
||||
///@cond PRIVATE
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* An undo command subclass for layout multiframe undo commands.
|
||||
*
|
||||
* QgsLayoutMultiFrameUndoCommand is a specific layout undo command which is
|
||||
* designed for use with QgsLayoutMultiFrames. It automatically handles
|
||||
* recreating a deleted multiframes when the undo stack rolls back past
|
||||
* the item deletion command.
|
||||
*
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsLayoutMultiFrameUndoCommand: public QgsAbstractLayoutUndoCommand
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsLayoutMultiFrameUndoCommand.
|
||||
* \param item associated layout item
|
||||
* \param text undo command descriptive text
|
||||
* \param id optional undo command id, used for automatic command merging
|
||||
* \param parent command
|
||||
*/
|
||||
QgsLayoutMultiFrameUndoCommand( QgsLayoutMultiFrame *frame, const QString &text, int id = 0, QUndoCommand *parent SIP_TRANSFERTHIS = nullptr );
|
||||
|
||||
bool mergeWith( const QUndoCommand *command ) override;
|
||||
|
||||
/**
|
||||
* Returns the layout associated with this command.
|
||||
*/
|
||||
QgsLayout *layout() const;
|
||||
|
||||
/**
|
||||
* Returns the associated multiframes's UUID, which uniquely identifies the frame
|
||||
* within the layout.
|
||||
*/
|
||||
QString multiFrameUuid() const;
|
||||
|
||||
protected:
|
||||
|
||||
void saveState( QDomDocument &stateDoc ) const override;
|
||||
void restoreState( QDomDocument &stateDoc ) override;
|
||||
|
||||
virtual QgsLayoutMultiFrame *recreateItem( int itemType, QgsLayout *layout ) SIP_FACTORY;
|
||||
|
||||
private:
|
||||
|
||||
QString mFrameUuid;
|
||||
QgsLayout *mLayout = nullptr;
|
||||
int mItemType = 0;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* An undo command subclass for layout multiframe deletion undo commands.
|
||||
*
|
||||
* QgsLayoutMultiFrameDeleteUndoCommand is a specific layout undo command which handles
|
||||
* layout multiframe deletion. When applied (e.g. as a result of a 'redo' action),
|
||||
* the associated layout multiframe is deleted and removed from the layout.
|
||||
*
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsLayoutMultiFrameDeleteUndoCommand: public QgsLayoutMultiFrameUndoCommand
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsLayoutMultiFrameDeleteUndoCommand.
|
||||
* \param item associated layout item
|
||||
* \param text undo command descriptive text
|
||||
* \param id optional undo command id, used for automatic command merging
|
||||
* \param parent command
|
||||
*/
|
||||
QgsLayoutMultiFrameDeleteUndoCommand( QgsLayoutMultiFrame *frame, const QString &text, int id = 0, QUndoCommand *parent SIP_TRANSFERTHIS = nullptr );
|
||||
bool mergeWith( const QUndoCommand *command ) override;
|
||||
void redo() override;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup core
|
||||
* An undo command subclass for layout item addition undo commands.
|
||||
*
|
||||
* QgsLayoutMultiFrameAddItemCommand is a specific layout undo command which handles
|
||||
* layout multiframe creation. When applied (e.g. as a result of a 'redo' action),
|
||||
* the associated layout multiframe is recreated and added to the layout.
|
||||
*
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
class CORE_EXPORT QgsLayoutMultiFrameAddItemCommand: public QgsLayoutMultiFrameUndoCommand
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor for QgsLayoutMultiFrameAddItemCommand.
|
||||
* \param item associated layout item
|
||||
* \param text undo command descriptive text
|
||||
* \param id optional undo command id, used for automatic command merging
|
||||
* \param parent command
|
||||
*/
|
||||
QgsLayoutMultiFrameAddItemCommand( QgsLayoutMultiFrame *frame, const QString &text, int id = 0, QUndoCommand *parent SIP_TRANSFERTHIS = nullptr );
|
||||
bool containsChange() const override;
|
||||
bool mergeWith( const QUndoCommand *command ) override;
|
||||
void undo() override;
|
||||
|
||||
};
|
||||
|
||||
///@endcond
|
||||
|
||||
#endif //QGSLAYOUTMULTIFRAMEUNDOCOMMAND_H
|
@ -22,6 +22,7 @@
|
||||
#include "qgsmultirenderchecker.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsproject.h"
|
||||
#include "qgslayoutitemhtml.h"
|
||||
|
||||
#include <QObject>
|
||||
#include "qgstest.h"
|
||||
@ -42,6 +43,7 @@ class TestQgsLayoutMultiFrame : public QObject
|
||||
void addRemovePage(); //test if page is added and removed for RepeatUntilFinished mode
|
||||
void undoRedo(); //test that combinations of frame/multiframe undo/redo don't crash
|
||||
void undoRedoRemovedFrame(); //test that undo doesn't crash with removed frames
|
||||
void registry();
|
||||
|
||||
private:
|
||||
QgsLayout *mLayout = nullptr;
|
||||
@ -60,6 +62,17 @@ class TestMultiFrame : public QgsLayoutMultiFrame
|
||||
|
||||
}
|
||||
|
||||
int type() const override
|
||||
{
|
||||
|
||||
return QgsLayoutItemRegistry::PluginItem + 1;
|
||||
}
|
||||
|
||||
QString stringType() const override
|
||||
{
|
||||
return QStringLiteral( "TestMultiFrame" );
|
||||
}
|
||||
|
||||
void render( QgsRenderContext &, const QRectF &, const int,
|
||||
const QStyleOptionGraphicsItem * ) override
|
||||
{
|
||||
@ -71,16 +84,6 @@ class TestMultiFrame : public QgsLayoutMultiFrame
|
||||
return QSizeF();
|
||||
}
|
||||
|
||||
bool writeXml( QDomElement &, QDomDocument &, bool ) const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool readXml( const QDomElement &, const QDomDocument &, bool ) override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
void TestQgsLayoutMultiFrame::initTestCase()
|
||||
@ -131,6 +134,8 @@ void TestQgsLayoutMultiFrame::layoutMethods()
|
||||
QPointer< TestMultiFrame > pMF( mF );
|
||||
QCOMPARE( l->multiFrames().count(), 1 );
|
||||
QVERIFY( l->multiFrames().contains( mF ) );
|
||||
QVERIFY( !l->multiFrameByUuid( QString() ) );
|
||||
QCOMPARE( l->multiFrameByUuid( mF->uuid() ), mF );
|
||||
|
||||
// try readding
|
||||
l->addMultiFrame( mF );
|
||||
@ -146,9 +151,11 @@ void TestQgsLayoutMultiFrame::layoutMethods()
|
||||
QCOMPARE( l->multiFrames().count(), 2 );
|
||||
QVERIFY( l->multiFrames().contains( mF ) );
|
||||
QVERIFY( l->multiFrames().contains( mF2 ) );
|
||||
QCOMPARE( l->multiFrameByUuid( mF2->uuid() ), mF2 );
|
||||
l->removeMultiFrame( mF2 );
|
||||
QCOMPARE( l->multiFrames().count(), 1 );
|
||||
QVERIFY( l->multiFrames().contains( mF ) );
|
||||
QVERIFY( !l->multiFrameByUuid( mF2->uuid() ) );
|
||||
|
||||
// should not be deleted
|
||||
QVERIFY( pMF2 );
|
||||
@ -245,13 +252,14 @@ void TestQgsLayoutMultiFrame::displayName()
|
||||
|
||||
void TestQgsLayoutMultiFrame::frameIsEmpty()
|
||||
{
|
||||
#if 0 //TODO
|
||||
QgsComposerHtml *htmlItem = new QgsComposerHtml( mLayout, false );
|
||||
QgsComposerFrame *frame1 = new QgsComposerFrame( mLayout, htmlItem, 0, 0, 100, 200 );
|
||||
QgsComposerFrame *frame2 = new QgsComposerFrame( mLayout, htmlItem, 0, 0, 100, 200 );
|
||||
QgsLayoutItemHtml *htmlItem = new QgsLayoutItemHtml( mLayout );
|
||||
QgsLayoutFrame *frame1 = new QgsLayoutFrame( mLayout, htmlItem );
|
||||
frame1->attemptSetSceneRect( QRectF( 0, 0, 100, 200 ) );
|
||||
QgsLayoutFrame *frame2 = new QgsLayoutFrame( mLayout, htmlItem );
|
||||
frame2->attemptSetSceneRect( QRectF( 0, 0, 100, 200 ) );
|
||||
htmlItem->addFrame( frame1 );
|
||||
htmlItem->addFrame( frame2 );
|
||||
htmlItem->setContentMode( QgsComposerHtml::ManualHtml );
|
||||
htmlItem->setContentMode( QgsLayoutItemHtml::ManualHtml );
|
||||
//short content, so frame 2 should be empty
|
||||
htmlItem->setHtml( QStringLiteral( "<p><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
@ -275,17 +283,16 @@ void TestQgsLayoutMultiFrame::frameIsEmpty()
|
||||
|
||||
mLayout->removeMultiFrame( htmlItem );
|
||||
delete htmlItem;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TestQgsLayoutMultiFrame::addRemovePage()
|
||||
{
|
||||
#if 0 //TODO
|
||||
QgsComposerHtml *htmlItem = new QgsComposerHtml( mLayout, false );
|
||||
QgsComposerFrame *frame1 = new QgsComposerFrame( mLayout, htmlItem, 0, 0, 100, 200 );
|
||||
QgsLayoutItemHtml *htmlItem = new QgsLayoutItemHtml( mLayout );
|
||||
QgsLayoutFrame *frame1 = new QgsLayoutFrame( mLayout, htmlItem );
|
||||
frame1->attemptSetSceneRect( QRectF( 0, 0, 100, 200 ) );
|
||||
htmlItem->addFrame( frame1 );
|
||||
htmlItem->setContentMode( QgsComposerHtml::ManualHtml );
|
||||
htmlItem->setResizeMode( QgsComposerMultiFrame::RepeatUntilFinished );
|
||||
htmlItem->setContentMode( QgsLayoutItemHtml::ManualHtml );
|
||||
htmlItem->setResizeMode( QgsLayoutMultiFrame::RepeatUntilFinished );
|
||||
|
||||
//short content, so should fit in one frame
|
||||
htmlItem->setHtml( QStringLiteral( "<p><i>Test manual <b>html</b></i></p>" ) );
|
||||
@ -293,55 +300,56 @@ void TestQgsLayoutMultiFrame::addRemovePage()
|
||||
|
||||
//should be one page
|
||||
QCOMPARE( htmlItem->frameCount(), 1 );
|
||||
QCOMPARE( mLayout->numPages(), 1 );
|
||||
QCOMPARE( mLayout->pageCollection()->pageCount(), 1 );
|
||||
|
||||
//long content, so we require 3 frames
|
||||
htmlItem->setHtml( QStringLiteral( "<p style=\"height: 2000px\"><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( htmlItem->frameCount(), 3 );
|
||||
QCOMPARE( mLayout->numPages(), 3 );
|
||||
QCOMPARE( mLayout->pageCollection()->pageCount(), 3 );
|
||||
|
||||
//..and back again..
|
||||
htmlItem->setHtml( QStringLiteral( "<p><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( htmlItem->frameCount(), 1 );
|
||||
QCOMPARE( mLayout->numPages(), 1 );
|
||||
QCOMPARE( mLayout->pageCollection()->pageCount(), 1 );
|
||||
|
||||
|
||||
//get a bit more complicated - add another item to page 3
|
||||
QgsComposerLabel *label1 = new QgsComposerLabel( mLayout );
|
||||
mLayout->addComposerLabel( label1 );
|
||||
label1->setItemPosition( 10, 10, 50, 50, QgsComposerItem::UpperLeft, false, 3 );
|
||||
QgsLayoutItemLabel *label1 = new QgsLayoutItemLabel( mLayout );
|
||||
mLayout->addLayoutItem( label1 );
|
||||
label1->attemptResize( QgsLayoutSize( 50, 50 ), false );
|
||||
|
||||
//long content, so we require 4 pages
|
||||
htmlItem->setHtml( QStringLiteral( "<p style=\"height: 3000px\"><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( htmlItem->frameCount(), 4 );
|
||||
QCOMPARE( mLayout->numPages(), 4 );
|
||||
QCOMPARE( mLayout->pageCollection()->pageCount(), 4 );
|
||||
|
||||
label1->attemptMove( QgsLayoutPoint( 10, 10 ), true, false, 2 );
|
||||
|
||||
//..and back again. Since there's an item on page 3, only page 4 should be removed
|
||||
htmlItem->setHtml( QStringLiteral( "<p><i>Test manual <b>html</b></i></p>" ) );
|
||||
htmlItem->loadHtml();
|
||||
|
||||
QCOMPARE( htmlItem->frameCount(), 1 );
|
||||
QCOMPARE( mLayout->numPages(), 3 );
|
||||
QCOMPARE( mLayout->pageCollection()->pageCount(), 3 );
|
||||
|
||||
mLayout->removeMultiFrame( htmlItem );
|
||||
delete htmlItem;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TestQgsLayoutMultiFrame::undoRedo()
|
||||
{
|
||||
#if 0 //TODO
|
||||
QgsComposerHtml *htmlItem = new QgsComposerHtml( mLayout, false );
|
||||
QgsComposerFrame *frame1 = new QgsComposerFrame( mLayout, htmlItem, 0, 0, 100, 200 );
|
||||
QgsLayoutItemHtml *htmlItem = new QgsLayoutItemHtml( mLayout );
|
||||
QgsLayoutFrame *frame1 = new QgsLayoutFrame( mLayout, htmlItem );
|
||||
frame1->attemptSetSceneRect( QRectF( 0, 0, 100, 200 ) );
|
||||
htmlItem->addFrame( frame1 );
|
||||
htmlItem->setContentMode( QgsComposerHtml::ManualHtml );
|
||||
htmlItem->setResizeMode( QgsComposerMultiFrame::RepeatUntilFinished );
|
||||
htmlItem->setContentMode( QgsLayoutItemHtml::ManualHtml );
|
||||
htmlItem->setResizeMode( QgsLayoutMultiFrame::RepeatUntilFinished );
|
||||
|
||||
//short content, so should fit in one frame
|
||||
htmlItem->setHtml( QStringLiteral( "<p>Test content</p>" ) );
|
||||
@ -350,76 +358,75 @@ void TestQgsLayoutMultiFrame::undoRedo()
|
||||
//do some combinations of undo/redo commands for both the frame and multiframe
|
||||
//to try to trigger a crash
|
||||
frame1->beginCommand( QStringLiteral( "move" ) );
|
||||
frame1->setSceneRect( QRectF( 10, 10, 20, 20 ) );
|
||||
frame1->attemptSetSceneRect( QRectF( 10, 10, 20, 20 ) );
|
||||
frame1->endCommand();
|
||||
frame1->beginCommand( QStringLiteral( "stroke" ), QgsComposerMergeCommand::ItemStrokeWidth );
|
||||
frame1->setFrameStrokeWidth( 4.0 );
|
||||
frame1->beginCommand( QStringLiteral( "stroke" ), QgsLayoutItem::UndoStrokeWidth );
|
||||
frame1->setFrameStrokeWidth( QgsLayoutMeasurement( 4.0 ) );
|
||||
frame1->endCommand();
|
||||
frame1->beginCommand( QStringLiteral( "stroke" ), QgsComposerMergeCommand::ItemStrokeWidth );
|
||||
frame1->setFrameStrokeWidth( 7.0 );
|
||||
frame1->beginCommand( QStringLiteral( "stroke" ), QgsLayoutItem::UndoStrokeWidth );
|
||||
frame1->setFrameStrokeWidth( QgsLayoutMeasurement( 7.0 ) );
|
||||
frame1->endCommand();
|
||||
|
||||
//multiframe commands
|
||||
mLayout->beginMultiFrameCommand( htmlItem, QStringLiteral( "maxbreak" ) );
|
||||
htmlItem->beginCommand( QStringLiteral( "maxbreak" ) );
|
||||
htmlItem->setMaxBreakDistance( 100 );
|
||||
mLayout->endMultiFrameCommand();
|
||||
htmlItem->endCommand();
|
||||
|
||||
//another frame command
|
||||
frame1->beginCommand( QStringLiteral( "bgcolor" ), QgsComposerMergeCommand::ItemOpacity );
|
||||
frame1->beginCommand( QStringLiteral( "bgcolor" ), QgsLayoutItem::UndoOpacity );
|
||||
frame1->setBackgroundColor( QColor( 255, 255, 0 ) );
|
||||
frame1->endCommand();
|
||||
frame1->beginCommand( QStringLiteral( "bgcolor" ), QgsComposerMergeCommand::ItemOpacity );
|
||||
frame1->beginCommand( QStringLiteral( "bgcolor" ), QgsLayoutItem::UndoOpacity );
|
||||
frame1->setBackgroundColor( QColor( 255, 0, 0 ) );
|
||||
frame1->endCommand();
|
||||
|
||||
//undo changes
|
||||
|
||||
//frame bg
|
||||
mLayout->undoStack()->undo();
|
||||
mLayout->undoStack()->stack()->undo();
|
||||
//multiframe max break
|
||||
mLayout->undoStack()->undo();
|
||||
mLayout->undoStack()->stack()->undo();
|
||||
//frame stroke width
|
||||
mLayout->undoStack()->undo();
|
||||
mLayout->undoStack()->stack()->undo();
|
||||
//frame move
|
||||
mLayout->undoStack()->undo();
|
||||
mLayout->undoStack()->stack()->undo();
|
||||
|
||||
//check result
|
||||
QCOMPARE( htmlItem->maxBreakDistance(), 10.0 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->frameStrokeWidth(), 0.3 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->frameStrokeWidth().length(), 0.3 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->pos(), QPointF( 0, 0 ) );
|
||||
QCOMPARE( htmlItem->frame( 0 )->backgroundColor(), QColor( 255, 255, 255 ) );
|
||||
|
||||
//now redo
|
||||
|
||||
//frame move
|
||||
mLayout->undoStack()->redo();
|
||||
mLayout->undoStack()->stack()->redo();
|
||||
//frame stroke width
|
||||
mLayout->undoStack()->redo();
|
||||
mLayout->undoStack()->stack()->redo();
|
||||
//multiframe max break
|
||||
mLayout->undoStack()->redo();
|
||||
mLayout->undoStack()->stack()->redo();
|
||||
//frame bg color
|
||||
mLayout->undoStack()->redo();
|
||||
mLayout->undoStack()->stack()->redo();
|
||||
|
||||
//check result
|
||||
QCOMPARE( htmlItem->maxBreakDistance(), 100.0 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->frameStrokeWidth(), 7.0 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->frameStrokeWidth().length(), 7.0 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->pos(), QPointF( 10, 10 ) );
|
||||
QCOMPARE( htmlItem->frame( 0 )->backgroundColor(), QColor( 255, 0, 0 ) );
|
||||
|
||||
mLayout->removeMultiFrame( htmlItem );
|
||||
delete htmlItem;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void TestQgsLayoutMultiFrame::undoRedoRemovedFrame()
|
||||
{
|
||||
#if 0 //TODO
|
||||
QgsComposerHtml *htmlItem = new QgsComposerHtml( mLayout, false );
|
||||
QgsComposerFrame *frame1 = new QgsComposerFrame( mLayout, htmlItem, 0, 0, 100, 200 );
|
||||
QgsLayoutItemHtml *htmlItem = new QgsLayoutItemHtml( mLayout );
|
||||
QgsLayoutFrame *frame1 = new QgsLayoutFrame( mLayout, htmlItem );
|
||||
frame1->attemptSetSceneRect( QRectF( 0, 0, 100, 200 ) );
|
||||
htmlItem->addFrame( frame1 );
|
||||
htmlItem->setContentMode( QgsComposerHtml::ManualHtml );
|
||||
htmlItem->setResizeMode( QgsComposerMultiFrame::RepeatUntilFinished );
|
||||
htmlItem->setContentMode( QgsLayoutItemHtml::ManualHtml );
|
||||
htmlItem->setResizeMode( QgsLayoutMultiFrame::RepeatUntilFinished );
|
||||
|
||||
//long content, so should require multiple frames
|
||||
htmlItem->setHtml( QStringLiteral( "<p style=\"height: 2000px\">Test content</p>" ) );
|
||||
@ -428,18 +435,18 @@ void TestQgsLayoutMultiFrame::undoRedoRemovedFrame()
|
||||
QVERIFY( htmlItem->frameCount() > 1 );
|
||||
|
||||
//do a command on the first frame
|
||||
htmlItem->frame( 0 )->beginCommand( QStringLiteral( "stroke" ), QgsComposerMergeCommand::ItemStrokeWidth );
|
||||
htmlItem->frame( 0 )->setFrameStrokeWidth( 4.0 );
|
||||
htmlItem->frame( 0 )->beginCommand( QStringLiteral( "stroke" ), QgsLayoutItem::UndoStrokeWidth );
|
||||
htmlItem->frame( 0 )->setFrameStrokeWidth( QgsLayoutMeasurement( 4.0 ) );
|
||||
htmlItem->frame( 0 )->endCommand();
|
||||
//do a command on the second frame
|
||||
htmlItem->frame( 1 )->beginCommand( QStringLiteral( "stroke" ), QgsComposerMergeCommand::ItemStrokeWidth );
|
||||
htmlItem->frame( 1 )->setFrameStrokeWidth( 8.0 );
|
||||
htmlItem->frame( 1 )->beginCommand( QStringLiteral( "stroke" ), QgsLayoutItem::UndoStrokeWidth );
|
||||
htmlItem->frame( 1 )->setFrameStrokeWidth( QgsLayoutMeasurement( 8.0 ) );
|
||||
htmlItem->frame( 1 )->endCommand();
|
||||
|
||||
//do a multiframe command which removes extra frames
|
||||
mLayout->beginMultiFrameCommand( htmlItem, QStringLiteral( "source" ) );
|
||||
htmlItem->beginCommand( QStringLiteral( "source" ) );
|
||||
htmlItem->setHtml( QStringLiteral( "<p style=\"height: 20px\">Test content</p>" ) );
|
||||
mLayout->endMultiFrameCommand();
|
||||
htmlItem->endCommand();
|
||||
|
||||
//wipes the second frame
|
||||
htmlItem->loadHtml();
|
||||
@ -449,36 +456,81 @@ void TestQgsLayoutMultiFrame::undoRedoRemovedFrame()
|
||||
//undo changes
|
||||
|
||||
//multiframe command
|
||||
mLayout->undoStack()->undo();
|
||||
mLayout->undoStack()->stack()->undo();
|
||||
//frame 2 command
|
||||
mLayout->undoStack()->undo();
|
||||
mLayout->undoStack()->stack()->undo();
|
||||
//frame 1 command
|
||||
mLayout->undoStack()->undo();
|
||||
|
||||
mLayout->undoStack()->stack()->undo();
|
||||
//check result
|
||||
QVERIFY( htmlItem->frameCount() > 1 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->frameStrokeWidth(), 0.3 );
|
||||
QCOMPARE( htmlItem->frame( 1 )->frameStrokeWidth(), 0.3 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->frameStrokeWidth().length(), 0.3 );
|
||||
QCOMPARE( htmlItem->frame( 1 )->frameStrokeWidth().length(), 0.3 );
|
||||
|
||||
//now redo
|
||||
|
||||
//frame 1 command
|
||||
mLayout->undoStack()->redo();
|
||||
mLayout->undoStack()->stack()->redo();
|
||||
//frame 2 command
|
||||
mLayout->undoStack()->redo();
|
||||
mLayout->undoStack()->stack()->redo();
|
||||
|
||||
//check result
|
||||
QVERIFY( htmlItem->frameCount() > 1 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->frameStrokeWidth(), 4.0 );
|
||||
QCOMPARE( htmlItem->frame( 1 )->frameStrokeWidth(), 8.0 );
|
||||
QCOMPARE( htmlItem->frame( 0 )->frameStrokeWidth().length(), 4.0 );
|
||||
QCOMPARE( htmlItem->frame( 1 )->frameStrokeWidth().length(), 8.0 );
|
||||
|
||||
//multiframe command
|
||||
mLayout->undoStack()->redo();
|
||||
mLayout->undoStack()->stack()->redo();
|
||||
QCOMPARE( htmlItem->frameCount(), 1 );
|
||||
|
||||
mLayout->removeMultiFrame( htmlItem );
|
||||
delete htmlItem;
|
||||
#endif
|
||||
}
|
||||
|
||||
void TestQgsLayoutMultiFrame::registry()
|
||||
{
|
||||
// test QgsLayoutItemRegistry
|
||||
QgsLayoutItemRegistry registry;
|
||||
|
||||
// empty registry
|
||||
QVERIFY( !registry.multiFrameMetadata( -1 ) );
|
||||
QVERIFY( registry.itemTypes().isEmpty() );
|
||||
QVERIFY( !registry.createMultiFrame( 1, nullptr ) );
|
||||
|
||||
auto create = []( QgsLayout * layout )->QgsLayoutMultiFrame*
|
||||
{
|
||||
return new TestMultiFrame( layout );
|
||||
};
|
||||
auto resolve = []( QVariantMap & props, const QgsPathResolver &, bool )
|
||||
{
|
||||
props.clear();
|
||||
};
|
||||
|
||||
QSignalSpy spyTypeAdded( ®istry, &QgsLayoutItemRegistry::multiFrameTypeAdded );
|
||||
|
||||
QgsLayoutMultiFrameMetadata *metadata = new QgsLayoutMultiFrameMetadata( QgsLayoutItemRegistry::PluginItem + 1, QStringLiteral( "TestMultiFrame" ), QIcon(), create, resolve );
|
||||
QVERIFY( registry.addLayoutMultiFrameType( metadata ) );
|
||||
QCOMPARE( spyTypeAdded.count(), 1 );
|
||||
QCOMPARE( spyTypeAdded.value( 0 ).at( 0 ).toInt(), QgsLayoutItemRegistry::PluginItem + 1 );
|
||||
QCOMPARE( spyTypeAdded.value( 0 ).at( 1 ).toString(), QStringLiteral( "TestMultiFrame" ) );
|
||||
// duplicate type id
|
||||
QVERIFY( !registry.addLayoutMultiFrameType( metadata ) );
|
||||
QCOMPARE( spyTypeAdded.count(), 1 );
|
||||
|
||||
//retrieve metadata
|
||||
QVERIFY( !registry.multiFrameMetadata( -1 ) );
|
||||
QCOMPARE( registry.multiFrameMetadata( QgsLayoutItemRegistry::PluginItem + 1 )->visibleName(), QStringLiteral( "TestMultiFrame" ) );
|
||||
QCOMPARE( registry.itemTypes().count(), 1 );
|
||||
QCOMPARE( registry.itemTypes().value( QgsLayoutItemRegistry::PluginItem + 1 ), QStringLiteral( "TestMultiFrame" ) );
|
||||
QgsLayout l( QgsProject::instance() );
|
||||
QgsLayoutMultiFrame *item = registry.createMultiFrame( QgsLayoutItemRegistry::PluginItem + 1, &l );
|
||||
QVERIFY( item );
|
||||
QVERIFY( dynamic_cast< TestMultiFrame *>( item ) );
|
||||
QVariantMap props;
|
||||
props.insert( QStringLiteral( "a" ), 5 );
|
||||
registry.resolvePaths( 1, props, QgsPathResolver(), true );
|
||||
QCOMPARE( props.size(), 1 );
|
||||
registry.resolvePaths( QgsLayoutItemRegistry::PluginItem + 1, props, QgsPathResolver(), true );
|
||||
QVERIFY( props.isEmpty() );
|
||||
}
|
||||
|
||||
QGSTEST_MAIN( TestQgsLayoutMultiFrame )
|
||||
|
Loading…
x
Reference in New Issue
Block a user