86 changes: 86 additions & 0 deletions src/core/composer/qgsaddremovemultiframecommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/***************************************************************************
qgsaddremovemultiframecommand.cpp
---------------------------------
begin : 2012-07-31
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* 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 "qgsaddremovemultiframecommand.h"
#include "qgscomposermultiframe.h"
#include "qgscomposition.h"


QgsAddRemoveMultiFrameCommand::QgsAddRemoveMultiFrameCommand( State s, QgsComposerMultiFrame* multiFrame, QgsComposition* c, const QString& text, QUndoCommand* parent ):
QUndoCommand( text, parent ), mMultiFrame( multiFrame ), mComposition( c ), mState(s), mFirstRun( true )
{
}

QgsAddRemoveMultiFrameCommand::QgsAddRemoveMultiFrameCommand(): mMultiFrame( 0 ), mComposition( 0 )
{
}

QgsAddRemoveMultiFrameCommand::~QgsAddRemoveMultiFrameCommand()
{
if( mState == Removed )
{
delete mMultiFrame;
}
}

void QgsAddRemoveMultiFrameCommand::redo()
{
if( checkFirstRun() )
{
return;
}
switchState();
}

void QgsAddRemoveMultiFrameCommand::undo()
{
if( checkFirstRun() )
{
return;
}
switchState();
}

void QgsAddRemoveMultiFrameCommand::switchState()
{
if( mComposition )
{
if( mState == Added )
{
mComposition->removeMultiFrame( mMultiFrame );
mState = Removed;
}
else
{
mComposition->addMultiFrame( mMultiFrame );
mState = Added;
}
}
}

bool QgsAddRemoveMultiFrameCommand::checkFirstRun()
{
if( mFirstRun )
{
mFirstRun = false;
return true;
}
else
{
return false;
}
}
54 changes: 54 additions & 0 deletions src/core/composer/qgsaddremovemultiframecommand.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/***************************************************************************
qgsaddremovemultiframecommand.h
-------------------------------
begin : 2012-07-31
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* 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 QGSADDREMOVEMULTIFRAMECOMMAND_H
#define QGSADDREMOVEMULTIFRAMECOMMAND_H

#include <QUndoCommand>

class QgsComposerMultiFrame;
class QgsComposition;

class CORE_EXPORT QgsAddRemoveMultiFrameCommand: public QUndoCommand
{
public:

enum State
{
Added = 0,
Removed
};

QgsAddRemoveMultiFrameCommand( State s, QgsComposerMultiFrame* multiFrame, QgsComposition* c, const QString& text, QUndoCommand* parent = 0 );
~QgsAddRemoveMultiFrameCommand();
void redo();
void undo();

private:
QgsAddRemoveMultiFrameCommand();

//changes between added / removed state
void switchState();
bool checkFirstRun();

QgsComposerMultiFrame* mMultiFrame;
QgsComposition* mComposition;
State mState;
bool mFirstRun;
};

#endif // QGSADDREMOVEMULTIFRAMECOMMAND_H
92 changes: 92 additions & 0 deletions src/core/composer/qgscomposerframe.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/***************************************************************************
qgscomposerframe.cpp
------------------------------------------------------------
begin : July 2012
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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 "qgscomposerframe.h"
#include "qgscomposermultiframe.h"

QgsComposerFrame::QgsComposerFrame( QgsComposition* c, QgsComposerMultiFrame* mf, double x, double y, double width, double height ):
QgsComposerItem( x, y, width, height, c ), mMultiFrame( mf )
{
}

QgsComposerFrame::QgsComposerFrame(): QgsComposerItem( 0, 0, 0, 0, 0 ), mMultiFrame( 0 )
{
}

QgsComposerFrame::~QgsComposerFrame()
{
}

bool QgsComposerFrame::writeXML( QDomElement& elem, QDomDocument & doc ) const
{
QDomElement frameElem = doc.createElement( "ComposerFrame" );
frameElem.setAttribute( "sectionX", QString::number( mSection.x() ) );
frameElem.setAttribute( "sectionY", QString::number( mSection.y() ) );
frameElem.setAttribute( "sectionWidth", QString::number( mSection.width() ) );
frameElem.setAttribute( "sectionHeight", QString::number( mSection.height() ) );
elem.appendChild( frameElem );
return _writeXML( frameElem, doc );
}

bool QgsComposerFrame::readXML( const QDomElement& itemElem, const QDomDocument& doc )
{
double x = itemElem.attribute( "sectionX" ).toDouble();
double y = itemElem.attribute( "sectionY" ).toDouble();
double width = itemElem.attribute( "sectionWidth" ).toDouble();
double height = itemElem.attribute( "sectionHeight" ).toDouble();
mSection = QRectF( x, y, width, height );
QDomElement composerItem = itemElem.firstChildElement( "ComposerItem" );
if ( composerItem.isNull() )
{
return false;
}
return _readXML( composerItem, doc );
}

void QgsComposerFrame::paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget )
{
if ( !painter )
{
return;
}

drawBackground( painter );
if ( mMultiFrame )
{
mMultiFrame->render( painter, mSection );
}

drawFrame( painter );
if ( isSelected() )
{
drawSelectionBoxes( painter );
}
}

void QgsComposerFrame::beginItemCommand( const QString& text )
{
if ( mComposition )
{
mComposition->beginMultiFrameCommand( multiFrame(), text );
}
}

void QgsComposerFrame::endItemCommand()
{
if ( mComposition )
{
mComposition->endMultiFrameCommand();
}
}
53 changes: 53 additions & 0 deletions src/core/composer/qgscomposerframe.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/***************************************************************************
qgscomposerframe.h
------------------------------------------------------------
begin : July 2012
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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 QGSCOMPOSERFRAME_H
#define QGSCOMPOSERFRAME_H

#include "qgscomposeritem.h"

class QgsComposition;
class QgsComposerMultiFrame;

/**Frame for html, table, text which can be divided onto several frames*/
class QgsComposerFrame: public QgsComposerItem
{
public:
QgsComposerFrame( QgsComposition* c, QgsComposerMultiFrame* mf, qreal x, qreal y, qreal width, qreal height );
~QgsComposerFrame();

/**Sets the part of this frame (relative to the total multiframe extent in mm)*/
void setContentSection( const QRectF& section ) { mSection = section; }

void paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget );

void beginItemCommand( const QString& text );
void endItemCommand();

bool writeXML( QDomElement& elem, QDomDocument & doc ) const;
bool readXML( const QDomElement& itemElem, const QDomDocument& doc );

int type() const { return ComposerFrame; }

QgsComposerMultiFrame* multiFrame() { return mMultiFrame; }


private:
QgsComposerFrame(); //forbidden
QgsComposerMultiFrame* mMultiFrame;
QRectF mSection;
};

#endif // QGSCOMPOSERFRAME_H
137 changes: 137 additions & 0 deletions src/core/composer/qgscomposerhtml.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/***************************************************************************
qgscomposerhtml.cpp
------------------------------------------------------------
begin : July 2012
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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 "qgscomposerhtml.h"
#include "qgscomposerframe.h"
#include "qgscomposition.h"
#include "qgsaddremovemultiframecommand.h"
#include <QCoreApplication>
#include <QPainter>
#include <QWebFrame>
#include <QWebPage>

QgsComposerHtml::QgsComposerHtml( QgsComposition* c, bool createUndoCommands ): QgsComposerMultiFrame( c, createUndoCommands ),
mWebPage( 0 ), mLoaded( false ), mHtmlUnitsToMM( 1.0 )
{
mHtmlUnitsToMM = htmlUnitsToMM();
mWebPage = new QWebPage();
QObject::connect( mWebPage, SIGNAL( loadFinished( bool ) ), this, SLOT( frameLoaded( bool ) ) );
if ( mComposition )
{
QObject::connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
}
}

QgsComposerHtml::QgsComposerHtml(): QgsComposerMultiFrame( 0, false ), mWebPage( 0 ), mLoaded( false ), mHtmlUnitsToMM( 1.0 )
{
}

QgsComposerHtml::~QgsComposerHtml()
{
delete mWebPage;
}

void QgsComposerHtml::setUrl( const QUrl& url )
{
if ( !mWebPage )
{
return;
}
mLoaded = false;

mUrl = url;
mWebPage->mainFrame()->load( mUrl );
while ( !mLoaded )
{
qApp->processEvents();
}
QSize contentsSize = mWebPage->mainFrame()->contentsSize();
mWebPage->setViewportSize( contentsSize );

mSize.setWidth( contentsSize.width() / mHtmlUnitsToMM );
mSize.setHeight( contentsSize.height() / mHtmlUnitsToMM );
recalculateFrameSizes();
emit changed();
}

void QgsComposerHtml::frameLoaded( bool ok )
{
Q_UNUSED( ok );
mLoaded = true;
}

QSizeF QgsComposerHtml::totalSize() const
{
return mSize;
}

void QgsComposerHtml::render( QPainter* p, const QRectF& renderExtent )
{
if ( !mWebPage )
{
return;
}

p->save();
p->scale( 1.0 / mHtmlUnitsToMM, 1.0 / mHtmlUnitsToMM );
p->translate( 0.0, -renderExtent.top() * mHtmlUnitsToMM );
mWebPage->mainFrame()->render( p, QRegion( renderExtent.left(), renderExtent.top() * mHtmlUnitsToMM, renderExtent.width() * mHtmlUnitsToMM, renderExtent.height() * mHtmlUnitsToMM ) );
p->restore();
}

double QgsComposerHtml::htmlUnitsToMM()
{
if ( !mComposition )
{
return 1.0;
}

return ( mComposition->printResolution() / 96.0 ); //webkit seems to assume a standard dpi of 96
}

void QgsComposerHtml::addFrame( QgsComposerFrame* frame, bool recalcFrameSizes )
{
mFrameItems.push_back( frame );
QObject::connect( frame, SIGNAL( sizeChanged() ), this, SLOT( recalculateFrameSizes() ) );
if ( mComposition )
{
mComposition->addComposerHtmlFrame( this, frame );
}

if ( recalcFrameSizes )
{
recalculateFrameSizes();
}
}

bool QgsComposerHtml::writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames ) const
{
QDomElement htmlElem = doc.createElement( "ComposerHtml" );
htmlElem.setAttribute( "url", mUrl.toString() );
bool state = _writeXML( htmlElem, doc, ignoreFrames );
elem.appendChild( htmlElem );
return state;
}

bool QgsComposerHtml::readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames )
{
deleteFrames();
QString urlString = itemElem.attribute( "url" );
if ( !urlString.isEmpty() )
{
setUrl( QUrl( urlString ) );
}
return _readXML( itemElem, doc, ignoreFrames );
}
56 changes: 56 additions & 0 deletions src/core/composer/qgscomposerhtml.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/***************************************************************************
qgscomposerhtml.h
------------------------------------------------------------
begin : July 2012
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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 QGSCOMPOSERHTML_H
#define QGSCOMPOSERHTML_H

#include "qgscomposermultiframe.h"
#include <QUrl>

class QWebPage;

class QgsComposerHtml: public QgsComposerMultiFrame
{
Q_OBJECT
public:
QgsComposerHtml( QgsComposition* c, bool createUndoCommands );
QgsComposerHtml();
~QgsComposerHtml();

void setUrl( const QUrl& url );
const QUrl& url() const { return mUrl; }

QSizeF totalSize() const;
void render( QPainter* p, const QRectF& renderExtent );

bool writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames = false ) const;
bool readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames = false );

void addFrame( QgsComposerFrame* frame, bool recalcFrameSizes = true );

private slots:
void frameLoaded( bool ok );

private:
QUrl mUrl;
QWebPage* mWebPage;
bool mLoaded;
QSizeF mSize; //total size in mm
double mHtmlUnitsToMM;

double htmlUnitsToMM(); //calculate scale factor
};

#endif // QGSCOMPOSERHTML_H
7 changes: 5 additions & 2 deletions src/core/composer/qgscomposeritem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include "qgscomposition.h"
#include "qgscomposeritem.h"
#include "qgscomposerframe.h"


#include <limits>
Expand Down Expand Up @@ -380,9 +381,9 @@ void QgsComposerItem::mouseReleaseEvent( QGraphicsSceneMouseEvent * event )
return;
}

beginCommand( tr( "Change item position" ) );
beginItemCommand( tr( "Change item position" ) );
changeItemRectangle( mouseMoveStopPoint, mMouseMoveStartPos, this, diffX, diffY, this );
endCommand();
endItemCommand();

//reset default action
mCurrentMouseMoveAction = QgsComposerItem::MoveItem;
Expand Down Expand Up @@ -724,6 +725,8 @@ void QgsComposerItem::setSceneRect( const QRectF& rectangle )
QTransform t;
t.translate( xTranslation, yTranslation );
setTransform( t );

emit sizeChanged();
}

void QgsComposerItem::drawBackground( QPainter* p )
Expand Down
9 changes: 8 additions & 1 deletion src/core/composer/qgscomposeritem.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,8 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
ComposerShape,
ComposerTable,
ComposerAttributeTable,
ComposerTextTable
ComposerTextTable,
ComposerFrame
};

/**Describes the action (move or resize in different directon) to be done during mouse move*/
Expand Down Expand Up @@ -189,10 +190,14 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem

const QgsComposition* composition() const {return mComposition;}

virtual void beginItemCommand( const QString& text ) { beginCommand( text ); }

/**Starts new composer undo command
@param commandText command title
@param c context for mergeable commands (unknown for non-mergeable commands*/
void beginCommand( const QString& commandText, QgsComposerMergeCommand::Context c = QgsComposerMergeCommand::Unknown );

virtual void endItemCommand() { endCommand(); }
/**Finish current command and push it onto the undo stack */
void endCommand();
void cancelCommand();
Expand Down Expand Up @@ -351,6 +356,8 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
void rotationChanged( double newRotation );
/**Used e.g. by the item widgets to update the gui elements*/
void itemChanged();
/**Emitted if the rectangle changes*/
void sizeChanged();
private:
// Label id (unique within the same composition)
QString mId;
Expand Down
190 changes: 190 additions & 0 deletions src/core/composer/qgscomposermultiframe.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/***************************************************************************
qgscomposermultiframe.cpp
------------------------------------------------------------
begin : July 2012
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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 "qgscomposermultiframe.h"
#include "qgscomposerframe.h"

QgsComposerMultiFrame::QgsComposerMultiFrame( QgsComposition* c, bool createUndoCommands ): mComposition( c ), mResizeMode( UseExistingFrames ), mCreateUndoCommands( createUndoCommands )
{
mComposition->addMultiFrame( this );
}

QgsComposerMultiFrame::QgsComposerMultiFrame(): mComposition( 0 ), mResizeMode( UseExistingFrames )
{
}

QgsComposerMultiFrame::~QgsComposerMultiFrame()
{
deleteFrames();
}

void QgsComposerMultiFrame::setResizeMode( ResizeMode mode )
{
if ( mode != mResizeMode )
{
mResizeMode = mode;
recalculateFrameSizes();
emit changed();
}
}

void QgsComposerMultiFrame::recalculateFrameSizes()
{
if ( mFrameItems.size() < 1 )
{
return;
}

QSizeF size = totalSize();
double totalHeight = size.height();

if ( totalHeight < 1 )
{
return;
}

double currentY = 0;
double currentHeight = 0;
QgsComposerFrame* currentItem = 0;

for ( int i = 0; i < mFrameItems.size(); ++i )
{
if ( currentY >= totalHeight )
{
if ( mResizeMode == ExtendToNextPage ) //remove unneeded frames in extent mode
{
for ( int j = mFrameItems.size(); j > i; --j )
{
removeFrame( j - 1 );
}
}
return;
}

currentItem = mFrameItems.value( i );
currentHeight = currentItem->rect().height();
currentItem->setContentSection( QRectF( 0, currentY, currentItem->rect().width(), currentHeight ) );
currentItem->update();
currentY += currentHeight;
}

//at end of frames but there is still content left. Add other pages if ResizeMode ==
if ( mResizeMode == ExtendToNextPage )
{
while ( currentY < totalHeight )
{
//find out on which page the lower left point of the last frame is
int page = currentItem->transform().dy() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );

//add new pages if necessary
if ( mComposition->numPages() < ( page + 2 ) )
{
mComposition->setNumPages( page + 2 );
}

//copy last frame
QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, currentItem->transform().dx(), currentItem->transform().dy() + mComposition->paperHeight() + mComposition->spaceBetweenPages(),
currentItem->rect().width(), currentItem->rect().height() );
newFrame->setContentSection( QRectF( 0, currentY, newFrame->rect().width(), newFrame->rect().height() ) );
currentY += newFrame->rect().height();
currentItem = newFrame;
addFrame( newFrame, false );
}
}
}

void QgsComposerMultiFrame::handleFrameRemoval( QgsComposerItem* item )
{
QgsComposerFrame* frame = dynamic_cast<QgsComposerFrame*>( item );
if ( !frame )
{
return;
}
int index = mFrameItems.indexOf( frame );
if ( index == -1 )
{
return;
}
mFrameItems.removeAt( index );
if ( mFrameItems.size() > 0 )
{
recalculateFrameSizes();
}
}

void QgsComposerMultiFrame::removeFrame( int i )
{
QgsComposerFrame* frameItem = mFrameItems[i];
if ( mComposition )
{
mComposition->removeComposerItem( frameItem );
}
}

void QgsComposerMultiFrame::update()
{
QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
for ( ; frameIt != mFrameItems.end(); ++frameIt )
{
( *frameIt )->update();
}
}

void QgsComposerMultiFrame::deleteFrames()
{
ResizeMode bkResizeMode = mResizeMode;
mResizeMode = UseExistingFrames;
mComposition->blockSignals( true );
QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
for ( ; frameIt != mFrameItems.end(); ++frameIt )
{
mComposition->removeComposerItem( *frameIt, false );
delete *frameIt;
}
mComposition->blockSignals( false );
mFrameItems.clear();
mResizeMode = bkResizeMode;
}

bool QgsComposerMultiFrame::_writeXML( QDomElement& elem, QDomDocument& doc, bool ignoreFrames ) const
{
elem.setAttribute( "resizeMode", mResizeMode );
if ( !ignoreFrames )
{
QList<QgsComposerFrame*>::const_iterator frameIt = mFrameItems.constBegin();
for ( ; frameIt != mFrameItems.constEnd(); ++frameIt )
{
( *frameIt )->writeXML( elem, doc );
}
}
return true;
}

bool QgsComposerMultiFrame::_readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames )
{
mResizeMode = ( ResizeMode )itemElem.attribute( "resizeMode", "0" ).toInt();
if ( !ignoreFrames )
{
QDomNodeList frameList = itemElem.elementsByTagName( "ComposerFrame" );
for ( int i = 0; i < frameList.size(); ++i )
{
QDomElement frameElem = frameList.at( i ).toElement();
QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, 0, 0, 0, 0 );
newFrame->readXML( frameElem, doc );
addFrame( newFrame );
}
}
return true;
}
91 changes: 91 additions & 0 deletions src/core/composer/qgscomposermultiframe.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/***************************************************************************
qgscomposermultiframe.h
------------------------------------------------------------
begin : July 2012
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************
* *
* 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 QGSCOMPOSERMULTIFRAME_H
#define QGSCOMPOSERMULTIFRAME_H

#include <QObject>
#include <QSizeF>

class QgsComposerFrame;
class QgsComposerItem;
class QgsComposition;
class QDomDocument;
class QDomElement;
class QRectF;
class QPainter;

/**Abstract base class for composer entries with the ability to distribute the content to several frames (items)*/
class QgsComposerMultiFrame: public QObject
{
Q_OBJECT
public:

enum ResizeMode
{
UseExistingFrames = 0,
ExtendToNextPage //duplicates last frame to next page to fit the total size
};

QgsComposerMultiFrame( QgsComposition* c, bool createUndoCommands );
virtual ~QgsComposerMultiFrame();
virtual QSizeF totalSize() const = 0;
virtual void render( QPainter* p, const QRectF& renderExtent ) = 0;

virtual void addFrame( QgsComposerFrame* frame, bool recalcFrameSizes = true ) = 0;

void removeFrame( int i );

void update();

void setResizeMode( ResizeMode mode );
ResizeMode resizeMode() const { return mResizeMode; }

virtual bool writeXML( QDomElement& elem, QDomDocument & doc, bool ignoreFrames = false ) const = 0;
bool _writeXML( QDomElement& elem, QDomDocument& doc, bool ignoreFrames = false ) const;

virtual bool readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames = false ) = 0;
bool _readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames = false );

QgsComposition* composition() { return mComposition; }

bool createUndoCommands() const { return mCreateUndoCommands; }
void setCreateUndoCommands( bool enabled ) { mCreateUndoCommands = enabled; }

/**Removes and deletes all frames from mComposition*/
void deleteFrames();

int nFrames() const { return mFrameItems.size(); }

protected:
QgsComposition* mComposition;
QList<QgsComposerFrame*> mFrameItems;
ResizeMode mResizeMode;
/**True: creates QgsMultiFrameCommands on internal changes (e.g. changing frames )*/
bool mCreateUndoCommands;

protected slots:
void recalculateFrameSizes();
/**Called before a frame is going to be removed (update frame list)*/
void handleFrameRemoval( QgsComposerItem* item );

private:
QgsComposerMultiFrame(); //forbidden

signals:
void changed();
};

#endif // QGSCOMPOSERMULTIFRAME_H
90 changes: 90 additions & 0 deletions src/core/composer/qgscomposermultiframecommand.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/***************************************************************************
qgscomposermultiframecommand.cpp
--------------------------------
begin : 2012-08-02
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* 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 "qgscomposermultiframecommand.h"
#include "qgscomposermultiframe.h"

QgsComposerMultiFrameCommand::QgsComposerMultiFrameCommand( QgsComposerMultiFrame* multiFrame, const QString& text, QUndoCommand* parent ):
QUndoCommand( text, parent ), mMultiFrame( multiFrame ), mFirstRun( true )
{
}

QgsComposerMultiFrameCommand::QgsComposerMultiFrameCommand(): QUndoCommand( "", 0 ), mMultiFrame( 0 ), mFirstRun( false )
{
}

QgsComposerMultiFrameCommand::~QgsComposerMultiFrameCommand()
{
}

void QgsComposerMultiFrameCommand::undo()
{
restoreState( mPreviousState );
}

void QgsComposerMultiFrameCommand::redo()
{
if ( checkFirstRun() )
{
return;
}
restoreState( mAfterState );
}

void QgsComposerMultiFrameCommand::savePreviousState()
{
saveState( mPreviousState );
}

void QgsComposerMultiFrameCommand::saveAfterState()
{
saveState( mAfterState );
}

void QgsComposerMultiFrameCommand::saveState( QDomDocument& stateDoc )
{
if ( mMultiFrame )
{
stateDoc.clear();
QDomElement documentElement = stateDoc.createElement( "ComposerMultiFrameState" );
mMultiFrame->writeXML( documentElement, stateDoc );
stateDoc.appendChild( documentElement );
}
}

void QgsComposerMultiFrameCommand::restoreState( QDomDocument& stateDoc )
{
if ( mMultiFrame )
{
mMultiFrame->readXML( stateDoc.documentElement().firstChild().toElement(), stateDoc );
}
}

bool QgsComposerMultiFrameCommand::checkFirstRun()
{
if ( !mFirstRun )
{
return false;
}
mFirstRun = false;
return true;
}

bool QgsComposerMultiFrameCommand::containsChange() const
{
return !( mPreviousState.isNull() || mAfterState.isNull() || mPreviousState.toString() == mAfterState.toString() );
}
55 changes: 55 additions & 0 deletions src/core/composer/qgscomposermultiframecommand.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/***************************************************************************
qgscomposermultiframecommand.h
------------------------------
begin : 2012-08-02
copyright : (C) 2012 by Marco Hugentobler
email : marco dot hugentobler at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* 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 QGSCOMPOSERMULTIFRAMECOMMAND_H
#define QGSCOMPOSERMULTIFRAMECOMMAND_H

#include <QUndoCommand>
#include <QDomDocument>

class QgsComposerMultiFrame;

class QgsComposerMultiFrameCommand: public QUndoCommand
{
public:
QgsComposerMultiFrameCommand( QgsComposerMultiFrame* multiFrame, const QString& text, QUndoCommand* parent = 0 );
~QgsComposerMultiFrameCommand();

void undo();
void redo();

void savePreviousState();
void saveAfterState();

/**Returns true if previous state and after state are valid and different*/
bool containsChange() const;

private:
QgsComposerMultiFrame* mMultiFrame;

QDomDocument mPreviousState;
QDomDocument mAfterState;

bool mFirstRun;

QgsComposerMultiFrameCommand(); //forbidden
void saveState( QDomDocument& stateDoc );
void restoreState( QDomDocument& stateDoc );
bool checkFirstRun();
};

#endif // QGSCOMPOSERMULTIFRAMECOMMAND_H
176 changes: 158 additions & 18 deletions src/core/composer/qgscomposition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
#include "qgscomposition.h"
#include "qgscomposeritem.h"
#include "qgscomposerarrow.h"
#include "qgscomposerframe.h"
#include "qgscomposerhtml.h"
#include "qgscomposerlabel.h"
#include "qgscomposerlegend.h"
#include "qgscomposermap.h"
Expand All @@ -25,6 +27,8 @@
#include "qgscomposerscalebar.h"
#include "qgscomposershape.h"
#include "qgscomposerattributetable.h"
#include "qgsaddremovemultiframecommand.h"
#include "qgscomposermultiframecommand.h"
#include "qgslogger.h"
#include "qgspaintenginehack.h"
#include "qgspaperitem.h"
Expand All @@ -37,7 +41,7 @@

QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer ):
QGraphicsScene( 0 ), mMapRenderer( mapRenderer ), mPlotStyle( QgsComposition::Preview ), mPageWidth( 297 ), mPageHeight( 210 ), mSpaceBetweenPages( 10 ), mPrintAsRaster( false ), mSelectionTolerance( 0.0 ),
mSnapToGrid( false ), mSnapGridResolution( 0.0 ), mSnapGridOffsetX( 0.0 ), mSnapGridOffsetY( 0.0 ), mActiveCommand( 0 )
mSnapToGrid( false ), mSnapGridResolution( 0.0 ), mSnapGridOffsetX( 0.0 ), mSnapGridOffsetY( 0.0 ), mActiveItemCommand( 0 ), mActiveMultiFrameCommand( 0 )
{
setBackgroundBrush( Qt::gray );
addPaperItem();
Expand All @@ -48,18 +52,28 @@ QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer ):

QgsComposition::QgsComposition():
QGraphicsScene( 0 ), mMapRenderer( 0 ), mPlotStyle( QgsComposition::Preview ), mPageWidth( 297 ), mPageHeight( 210 ), mSpaceBetweenPages( 10 ), mPrintAsRaster( false ),
mSelectionTolerance( 0.0 ), mSnapToGrid( false ), mSnapGridResolution( 0.0 ), mSnapGridOffsetX( 0.0 ), mSnapGridOffsetY( 0.0 ), mActiveCommand( 0 )
mSelectionTolerance( 0.0 ), mSnapToGrid( false ), mSnapGridResolution( 0.0 ), mSnapGridOffsetX( 0.0 ), mSnapGridOffsetY( 0.0 ), mActiveItemCommand( 0 ), mActiveMultiFrameCommand( 0 )
{
loadSettings();
}

QgsComposition::~QgsComposition()
{
removePaperItems();

QSet<QgsComposerMultiFrame*>::iterator multiFrameIt = mMultiFrames.begin();
for ( ; multiFrameIt != mMultiFrames.end(); ++multiFrameIt )
{
delete *multiFrameIt;
}
mMultiFrames.clear();

// make sure that all composer items are removed before
// this class is deconstructed - to avoid segfaults
// when composer items access in destructor composition that isn't valid anymore
clear();
delete mActiveItemCommand;
delete mActiveMultiFrameCommand;
}

void QgsComposition::setPaperSize( double width, double height )
Expand Down Expand Up @@ -236,6 +250,28 @@ bool QgsComposition::writeXML( QDomElement& composerElem, QDomDocument& doc )
compositionElem.setAttribute( "printResolution", mPrintResolution );
compositionElem.setAttribute( "printAsRaster", mPrintAsRaster );

//save items except paper items and frame items (they are saved with the corresponding multiframe)
QList<QGraphicsItem*> itemList = items();
QList<QGraphicsItem*>::const_iterator itemIt = itemList.constBegin();
for ( ; itemIt != itemList.constEnd(); ++itemIt )
{
const QgsComposerItem* composerItem = dynamic_cast<const QgsComposerItem*>( *itemIt );
if ( composerItem )
{
if ( composerItem->type() != QgsComposerItem::ComposerPaper && composerItem->type() != QgsComposerItem::ComposerFrame )
{
composerItem->writeXML( compositionElem, doc );
}
}
}

//save multiframes
QSet<QgsComposerMultiFrame*>::const_iterator multiFrameIt = mMultiFrames.constBegin();
for ( ; multiFrameIt != mMultiFrames.constEnd(); ++multiFrameIt )
{
( *multiFrameIt )->writeXML( compositionElem, doc );
}

composerElem.appendChild( compositionElem );

return true;
Expand Down Expand Up @@ -430,6 +466,16 @@ void QgsComposition::addItemsFromXML( const QDomElement& elem, const QDomDocumen
pushAddRemoveCommand( newTable, tr( "Table added" ) );
}
}
//html
QDomNodeList composerHtmlList = elem.elementsByTagName( "ComposerHtml" );
for ( int i = 0; i < composerHtmlList.size(); ++i )
{
QDomElement currentHtmlElem = composerHtmlList.at( i ).toElement();
QgsComposerHtml* newHtml = new QgsComposerHtml( this, false );
newHtml->readXML( currentHtmlElem, doc );
newHtml->setCreateUndoCommands( true );
this->addMultiFrame( newHtml );
}
}

void QgsComposition::addItemToZList( QgsComposerItem* item )
Expand Down Expand Up @@ -960,45 +1006,79 @@ void QgsComposition::saveSettings()

void QgsComposition::beginCommand( QgsComposerItem* item, const QString& commandText, QgsComposerMergeCommand::Context c )
{
delete mActiveCommand;
delete mActiveItemCommand;
if ( !item )
{
mActiveCommand = 0;
mActiveItemCommand = 0;
return;
}

if ( c == QgsComposerMergeCommand::Unknown )
{
mActiveCommand = new QgsComposerItemCommand( item, commandText );
mActiveItemCommand = new QgsComposerItemCommand( item, commandText );
}
else
{
mActiveCommand = new QgsComposerMergeCommand( c, item, commandText );
mActiveItemCommand = new QgsComposerMergeCommand( c, item, commandText );
}
mActiveCommand->savePreviousState();
mActiveItemCommand->savePreviousState();
}

void QgsComposition::endCommand()
{
if ( mActiveCommand )
if ( mActiveItemCommand )
{
mActiveCommand->saveAfterState();
if ( mActiveCommand->containsChange() ) //protect against empty commands
mActiveItemCommand->saveAfterState();
if ( mActiveItemCommand->containsChange() ) //protect against empty commands
{
mUndoStack.push( mActiveCommand );
mUndoStack.push( mActiveItemCommand );
}
else
{
delete mActiveCommand;
delete mActiveItemCommand;
}
mActiveCommand = 0;
mActiveItemCommand = 0;
}
}

void QgsComposition::cancelCommand()
{
delete mActiveCommand;
mActiveCommand = 0;
delete mActiveItemCommand;
mActiveItemCommand = 0;
}

void QgsComposition::beginMultiFrameCommand( QgsComposerMultiFrame* multiFrame, const QString& text )
{
delete mActiveMultiFrameCommand;
mActiveMultiFrameCommand = new QgsComposerMultiFrameCommand( multiFrame, text );
mActiveMultiFrameCommand->savePreviousState();
}

void QgsComposition::endMultiFrameCommand()
{
if ( mActiveMultiFrameCommand )
{
mActiveMultiFrameCommand->saveAfterState();
if ( mActiveMultiFrameCommand->containsChange() )
{
mUndoStack.push( mActiveMultiFrameCommand );
}
else
{
delete mActiveMultiFrameCommand;
}
mActiveMultiFrameCommand = 0;
}
}

void QgsComposition::addMultiFrame( QgsComposerMultiFrame* multiFrame )
{
mMultiFrames.insert( multiFrame );
}

void QgsComposition::removeMultiFrame( QgsComposerMultiFrame* multiFrame )
{
mMultiFrames.remove( multiFrame );
}

void QgsComposition::addComposerArrow( QgsComposerArrow* arrow )
Expand Down Expand Up @@ -1096,7 +1176,16 @@ void QgsComposition::addComposerTable( QgsComposerAttributeTable* table )
emit selectedItemChanged( table );
}

void QgsComposition::removeComposerItem( QgsComposerItem* item )
void QgsComposition::addComposerHtmlFrame( QgsComposerHtml* html, QgsComposerFrame* frame )
{
addItem( frame );
emit composerHtmlFrameAdded( html, frame );
clearSelection();
frame->setSelected( true );
emit selectedItemChanged( frame );
}

void QgsComposition::removeComposerItem( QgsComposerItem* item, bool createCommand )
{
QgsComposerMap* map = dynamic_cast<QgsComposerMap *>( item );
if ( !map || !map->isDrawing() ) //don't delete a composer map while it draws
Expand All @@ -1123,8 +1212,46 @@ void QgsComposition::removeComposerItem( QgsComposerItem* item )
}
else
{
emit itemRemoved( item );
pushAddRemoveCommand( item, tr( "Item deleted" ), QgsAddRemoveItemCommand::Removed );
bool frameItem = ( item->type() == QgsComposerItem::ComposerFrame );
QgsComposerMultiFrame* multiFrame = 0;
if ( createCommand )
{
if ( frameItem ) //multiframe tracks item changes
{
multiFrame = static_cast<QgsComposerFrame*>( item )->multiFrame();
item->beginItemCommand( tr( "Frame deleted" ) );
emit itemRemoved( item );
item->endItemCommand();
}
else
{
emit itemRemoved( item );
pushAddRemoveCommand( item, tr( "Item deleted" ), QgsAddRemoveItemCommand::Removed );
}
}
else
{
emit itemRemoved( item );
}

//check if there are frames left. If not, remove the multi frame
if ( frameItem && multiFrame )
{
if ( multiFrame->nFrames() < 1 )
{
removeMultiFrame( multiFrame );
if ( createCommand )
{
QgsAddRemoveMultiFrameCommand* command = new QgsAddRemoveMultiFrameCommand( QgsAddRemoveMultiFrameCommand::Removed,
multiFrame, this, tr( "Multiframe removed" ) );
undoStack()->push( command );
}
else
{
delete multiFrame;
}
}
}
}
}
}
Expand Down Expand Up @@ -1207,6 +1334,19 @@ void QgsComposition::sendItemAddedSignal( QgsComposerItem* item )
emit selectedItemChanged( table );
return;
}
QgsComposerFrame* frame = dynamic_cast<QgsComposerFrame*>( item );
if ( frame )
{
//emit composerFrameAdded( multiframe, frame, );
QgsComposerMultiFrame* mf = frame->multiFrame();
QgsComposerHtml* html = dynamic_cast<QgsComposerHtml*>( mf );
if ( html )
{
emit composerHtmlFrameAdded( html, frame );
}
emit selectedItemChanged( frame );
return;
}
}

void QgsComposition::updatePaperItems()
Expand Down
26 changes: 23 additions & 3 deletions src/core/composer/qgscomposition.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,21 @@
#include <QDomDocument>
#include <QGraphicsScene>
#include <QLinkedList>
#include <QSet>
#include <QUndoStack>

#include "qgscomposeritemcommand.h"
#include "qgsaddremoveitemcommand.h"
#include "qgscomposeritemcommand.h"

class QgsComposerFrame;
class QgsComposerItem;
class QgsComposerMap;
class QgsPaperItem;
class QGraphicsRectItem;
class QgsMapRenderer;
class QDomElement;
class QgsComposerArrow;
class QgsComposerHtml;
class QgsComposerItem;
class QgsComposerLabel;
class QgsComposerLegend;
Expand All @@ -39,6 +42,8 @@ class QgsComposerPicture;
class QgsComposerScaleBar;
class QgsComposerShape;
class QgsComposerAttributeTable;
class QgsComposerMultiFrame;
class QgsComposerMultiFrameCommand;

/** \ingroup MapComposer
* Graphics scene for map printing. The class manages the paper item which always
Expand Down Expand Up @@ -198,6 +203,13 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
/**Deletes current command*/
void cancelCommand();

void beginMultiFrameCommand( QgsComposerMultiFrame* multiFrame, const QString& text );
void endMultiFrameCommand();

/**Adds multiframe. The object is owned by QgsComposition until removeMultiFrame is called*/
void addMultiFrame( QgsComposerMultiFrame* multiFrame );
/**Removes multi frame (but does not delete it)*/
void removeMultiFrame( QgsComposerMultiFrame* multiFrame );
/**Adds an arrow item to the graphics scene and advices composer to create a widget for it (through signal)*/
void addComposerArrow( QgsComposerArrow* arrow );
/**Adds label to the graphics scene and advices composer to create a widget for it (through signal)*/
Expand All @@ -214,9 +226,11 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
void addComposerShape( QgsComposerShape* shape );
/**Adds a composer table to the graphics scene and advices composer to create a widget for it (through signal)*/
void addComposerTable( QgsComposerAttributeTable* table );
/**Adds composer html frame and advices composer to create a widget for it (through signal)*/
void addComposerHtmlFrame( QgsComposerHtml* html, QgsComposerFrame* frame );

/**Remove item from the graphics scene. Additionally to QGraphicsScene::removeItem, this function considers undo/redo command*/
void removeComposerItem( QgsComposerItem* item );
void removeComposerItem( QgsComposerItem* item, bool createCommand = true );

/**Convenience function to create a QgsAddRemoveItemCommand, connect its signals and push it to the undo stack*/
void pushAddRemoveCommand( QgsComposerItem* item, const QString& text, QgsAddRemoveItemCommand::State state = QgsAddRemoveItemCommand::Added );
Expand Down Expand Up @@ -252,6 +266,9 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
/**Maintains z-Order of items. Starts with item at position 1 (position 0 is always paper item)*/
QLinkedList<QgsComposerItem*> mItemZList;

/**List multiframe objects*/
QSet<QgsComposerMultiFrame*> mMultiFrames;

/**Dpi for printout*/
int mPrintResolution;

Expand All @@ -271,7 +288,8 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene

QUndoStack mUndoStack;

QgsComposerItemCommand* mActiveCommand;
QgsComposerItemCommand* mActiveItemCommand;
QgsComposerMultiFrameCommand* mActiveMultiFrameCommand;

QgsComposition(); //default constructor is forbidden

Expand All @@ -298,6 +316,8 @@ class CORE_EXPORT QgsComposition: public QGraphicsScene
void selectedItemChanged( QgsComposerItem* selected );
/**Is emitted when new composer arrow has been added to the view*/
void composerArrowAdded( QgsComposerArrow* arrow );
/**Is emitted when a new composer html has been added to the view*/
void composerHtmlFrameAdded( QgsComposerHtml* html, QgsComposerFrame* frame );
/**Is emitted when new composer label has been added to the view*/
void composerLabelAdded( QgsComposerLabel* label );
/**Is emitted when new composer map has been added to the view*/
Expand Down
23 changes: 23 additions & 0 deletions src/gui/qgscomposerview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@

#include "qgscomposerview.h"
#include "qgscomposerarrow.h"
#include "qgscomposerframe.h"
#include "qgscomposerhtml.h"
#include "qgscomposerlabel.h"
#include "qgscomposerlegend.h"
#include "qgscomposermap.h"
Expand All @@ -33,6 +35,7 @@
#include "qgscomposershape.h"
#include "qgscomposerattributetable.h"
#include "qgslogger.h"
#include "qgsaddremovemultiframecommand.h"

QgsComposerView::QgsComposerView( QWidget* parent, const char* name, Qt::WFlags f )
: QGraphicsView( parent )
Expand Down Expand Up @@ -126,6 +129,7 @@ void QgsComposerView::mousePressEvent( QMouseEvent* e )
case AddRectangle:
case AddTriangle:
case AddEllipse:
case AddHtml:
{
QTransform t;
mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
Expand Down Expand Up @@ -317,6 +321,24 @@ void QgsComposerView::mouseReleaseEvent( QMouseEvent* e )
}
break;

case AddHtml:
if ( composition() )
{
QgsComposerHtml* composerHtml = new QgsComposerHtml( composition(), true );
QgsAddRemoveMultiFrameCommand* command = new QgsAddRemoveMultiFrameCommand( QgsAddRemoveMultiFrameCommand::Added,
composerHtml, composition(), tr( "Html item added" ) );
composition()->undoStack()->push( command );
QgsComposerFrame* frame = new QgsComposerFrame( composition(), composerHtml, mRubberBandItem->transform().dx(),
mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(),
mRubberBandItem->rect().height() );
composition()->beginMultiFrameCommand( composerHtml, tr( "Html frame added" ) );
composerHtml->addFrame( frame );
composition()->endMultiFrameCommand();
scene()->removeItem( mRubberBandItem );
delete mRubberBandItem;
mRubberBandItem = 0;
emit actionFinished();
}
default:
break;
}
Expand Down Expand Up @@ -359,6 +381,7 @@ void QgsComposerView::mouseMoveEvent( QMouseEvent* e )
case AddRectangle:
case AddTriangle:
case AddEllipse:
case AddHtml:
//adjust rubber band item
{
double x = 0;
Expand Down
1 change: 1 addition & 0 deletions src/gui/qgscomposerview.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class GUI_EXPORT QgsComposerView: public QGraphicsView
{
Select = 0, // Select/Move item
AddArrow, //add arrow
AddHtml,
AddMap, // add new map
AddLegend, // add vector legend
AddLabel, // add label
Expand Down
12 changes: 12 additions & 0 deletions src/ui/qgscomposerbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
<addaction name="mActionAddNewScalebar"/>
<addaction name="mActionAddArrow"/>
<addaction name="mActionAddTable"/>
<addaction name="mActionAddHtml"/>
<addaction name="separator"/>
<addaction name="mActionSelectMoveItem"/>
<addaction name="mActionMoveItemContent"/>
Expand Down Expand Up @@ -443,6 +444,17 @@
<string>Add Ellipse</string>
</property>
</action>
<action name="mActionAddHtml">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Add html</string>
</property>
<property name="toolTip">
<string>Add html frame</string>
</property>
</action>
</widget>
<resources>
<include location="../../images/images.qrc"/>
Expand Down
70 changes: 70 additions & 0 deletions src/ui/qgscomposerhtmlwidgetbase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsComposerHtmlWidgetBase</class>
<widget class="QWidget" name="QgsComposerHtmlWidgetBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>243</width>
<height>116</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QToolBox" name="mToolBox">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="page">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>225</width>
<height>72</height>
</rect>
</property>
<attribute name="label">
<string>HTML</string>
</attribute>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="2">
<widget class="QToolButton" name="mFileToolButton">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="mUrlLineEdit"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="mUrlLabel">
<property name="text">
<string>URL</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="mResizeModeLabel">
<property name="text">
<string>Resize mode</string>
</property>
</widget>
</item>
<item row="0" column="1" colspan="2">
<widget class="QComboBox" name="mResizeModeComboBox"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
1 change: 1 addition & 0 deletions tests/src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,4 @@ ADD_QGIS_TEST(ziplayertest testziplayer.cpp)
ADD_QGIS_TEST(dataitemtest testqgsdataitem.cpp)
ADD_QGIS_TEST(composermaptest testqgscomposermap.cpp)
ADD_QGIS_TEST(stylev2test testqgsstylev2.cpp)
ADD_QGIS_TEST(composerhtmltest testqgscomposerhtml.cpp )
11 changes: 6 additions & 5 deletions tests/src/core/qgscompositionchecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,20 @@ bool QgsCompositionChecker::testComposition( int page )
return false;
}

#if 0 //fake mode to generate expected image
#if 0
//fake mode to generate expected image
//assume 300 dpi and size of the control image 3507 * 2480
QImage outputImage( QSize( 3507, 2480 ), QImage::Format_ARGB32 );
mComposition->setPlotStyle( QgsComposition::Print );
outputImage.setDotsPerMeterX( 300 / 25.4 * 1000 );
outputImage.setDotsPerMeterY( 300 / 25.4 * 1000 );
outputImage.fill( 0 );
QPainter p( &outputImage );
QRectF sourceArea( 0, 0, mComposition->paperWidth(), mComposition->paperHeight() );
QRectF targetArea( 0, 0, 3507, 2480 );
mComposition->render( &p, targetArea, sourceArea );
//QRectF sourceArea( 0, 0, mComposition->paperWidth(), mComposition->paperHeight() );
//QRectF targetArea( 0, 0, 3507, 2480 );
mComposition->renderPage( &p, page );
p.end();
outputImage.save( "/tmp/composermap_control.png", "PNG" );
outputImage.save( "/tmp/composerhtml_table_control.png", "PNG" );
return false;
#endif //0

Expand Down
111 changes: 111 additions & 0 deletions tests/src/core/testqgscomposerhtml.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/***************************************************************************
testqgscomposerhtml.cpp
-----------------------
begin : August 2012
copyright : (C) 2012 by Marco Hugentobler
email : marco at sourcepole dot ch
***************************************************************************/

/***************************************************************************
* *
* 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 "qgscomposerhtml.h"
#include "qgscomposerframe.h"
#include "qgscomposition.h"
#include "qgscompositionchecker.h"
#include <QObject>
#include <QtTest>

class TestQgsComposerHtml: public QObject
{
Q_OBJECT;
private slots:
void initTestCase();// will be called before the first testfunction is executed.
void cleanupTestCase();// will be called after the last testfunction was executed.
void init();// will be called before each testfunction is executed.
void cleanup();// will be called after every testfunction.
void table(); //test if rendering of the composition with composr map is correct
void tableMultiFrame(); //tests multiframe capabilities of composer html
private:
QgsComposition* mComposition;
};

void TestQgsComposerHtml::initTestCase()
{
mComposition = new QgsComposition( 0 );
mComposition->setPaperSize( 297, 210 ); //A4 landscape
}

void TestQgsComposerHtml::cleanupTestCase()
{
delete mComposition;
}

void TestQgsComposerHtml::init()
{

}

void TestQgsComposerHtml::cleanup()
{

}

void TestQgsComposerHtml::table()
{
QgsComposerHtml* htmlItem = new QgsComposerHtml( mComposition, false );
QgsComposerFrame* htmlFrame = new QgsComposerFrame( mComposition, htmlItem, 0, 0, 100, 200 );
htmlItem->addFrame( htmlFrame );
htmlItem->setUrl( QUrl( QString( "file:///%1" ).arg( QString( TEST_DATA_DIR ) + QDir::separator() + "html_table.html" ) ) );
QgsCompositionChecker checker( "Composer html table", mComposition, QString( QString( TEST_DATA_DIR ) + QDir::separator() +
"control_images" + QDir::separator() + "expected_composerhtml" + QDir::separator() + "composerhtml_table.png" ) );
bool result = checker.testComposition();
mComposition->removeMultiFrame( htmlItem );
delete htmlItem;
QVERIFY( result );
}

void TestQgsComposerHtml::tableMultiFrame()
{
QgsComposerHtml* htmlItem = new QgsComposerHtml( mComposition, false );
QgsComposerFrame* htmlFrame = new QgsComposerFrame( mComposition, htmlItem, 10, 10, 100, 50 );
htmlItem->addFrame( htmlFrame );
htmlItem->setResizeMode( QgsComposerMultiFrame::ExtendToNextPage );
bool result = true;
//page1
htmlItem->setUrl( QUrl( QString( "file:///%1" ).arg( QString( TEST_DATA_DIR ) + QDir::separator() + "html_table.html" ) ) );
QgsCompositionChecker checker1( "Composer html table", mComposition, QString( QString( TEST_DATA_DIR ) + QDir::separator() +
"control_images" + QDir::separator() + "expected_composerhtml" + QDir::separator() + "composerhtml_table_multiframe1.png" ) );
if ( !checker1.testComposition( 0 ) )
{
result = false;
}
//page2
QgsCompositionChecker checker2( "Composer html table", mComposition, QString( QString( TEST_DATA_DIR ) + QDir::separator() +
"control_images" + QDir::separator() + "expected_composerhtml" + QDir::separator() + "composerhtml_table_multiframe2.png" ) );
if ( !checker2.testComposition( 1 ) )
{
result = false;
}
//page 3
QgsCompositionChecker checker3( "Composer html table", mComposition, QString( QString( TEST_DATA_DIR ) + QDir::separator() +
"control_images" + QDir::separator() + "expected_composerhtml" + QDir::separator() + "composerhtml_table_multiframe3.png" ) );
if ( !checker3.testComposition( 2 ) )
{
result = false;
}

mComposition->removeMultiFrame( htmlItem );
delete htmlItem;
QVERIFY( result );
}


QTEST_MAIN( TestQgsComposerHtml )
#include "moc_testqgscomposerhtml.cxx"
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions tests/testdata/html_table.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<table border="1" style="font-size:12pt; ">
<tbody>
<tr><td>1 Foo data</td><td>Bar data</td></tr>
<tr><td>2 Foo data</td><td>Bar data</td></tr>
<tr><td>3 Foo data</td><td>Bar data</td></tr>
<tr><td>4 Foo data</td><td>Bar data</td></tr>
<tr><td>5 Foo data</td><td>Bar data</td></tr>
</tbody>
</table>
<table>