Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
[FEATURE][composer] Allow manual control of column widths for attribu…
…te table items.
  • Loading branch information
nyalldawson committed Sep 22, 2014
1 parent 97805b6 commit b893cb2
Show file tree
Hide file tree
Showing 9 changed files with 161 additions and 10 deletions.
14 changes: 14 additions & 0 deletions python/core/composer/qgscomposertablecolumn.sip
Expand Up @@ -25,6 +25,20 @@ class QgsComposerTableColumn: QObject
* @see writeXML
*/
virtual bool readXML( const QDomElement& columnElem );

/**Returns the width for a column.
* @returns column width in mm, or 0 if column width is automatically calculated.
* @note added in 2.5
* @see setWidth
*/
double width() const;

/**Sets the width for a column.
* @param width column width in mm, or 0 if column width is to be automatically calculated.
* @note added in 2.5
* @see width
*/
void setWidth( const double width );

/**Returns the heading for a column, which is the value displayed in the columns
* header cell.
Expand Down
52 changes: 51 additions & 1 deletion src/app/composer/qgsattributeselectiondialog.cpp
Expand Up @@ -217,6 +217,52 @@ void QgsComposerColumnSortOrderDelegate::updateEditorGeometry( QWidget* editor,
}


//
// QgsComposerColumnWidthDelegate
//

QgsComposerColumnWidthDelegate::QgsComposerColumnWidthDelegate( QObject *parent )
: QItemDelegate( parent )
{

}

QWidget *QgsComposerColumnWidthDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
Q_UNUSED( index );
Q_UNUSED( option );
QDoubleSpinBox *editor = new QDoubleSpinBox( parent );
editor->setMinimum( 0 );
editor->setMaximum( 1000 );
editor->setDecimals( 2 );
editor->setSuffix( tr( " mm" ) );
editor->setSpecialValueText( tr( "Automatic" ) );
return editor;
}

void QgsComposerColumnWidthDelegate::setEditorData( QWidget *editor, const QModelIndex &index ) const
{
int value = index.model()->data( index, Qt::EditRole ).toInt();

QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>( editor );
spinBox->setValue( value );
}

void QgsComposerColumnWidthDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const
{
QDoubleSpinBox *spinBox = static_cast<QDoubleSpinBox*>( editor );
spinBox->interpretText();
int value = spinBox->value();

model->setData( index, value, Qt::EditRole );
}

void QgsComposerColumnWidthDelegate::updateEditorGeometry( QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index ) const
{
Q_UNUSED( index );
editor->setGeometry( option.rect );
}


// QgsAttributeSelectionDialog

Expand All @@ -232,7 +278,8 @@ QgsAttributeSelectionDialog::QgsAttributeSelectionDialog( QgsComposerAttributeTa
mAvailableSortProxyModel( 0 ),
mAvailableSortProxyModelV1( 0 ),
mColumnAlignmentDelegate( 0 ),
mColumnSortOrderDelegate( 0 )
mColumnSortOrderDelegate( 0 ),
mColumnWidthDelegate( 0 )
{
setupUi( this );

Expand All @@ -250,6 +297,8 @@ QgsAttributeSelectionDialog::QgsAttributeSelectionDialog( QgsComposerAttributeTa
mColumnsTableView->setItemDelegateForColumn( 0, mColumnSourceDelegate );
mColumnAlignmentDelegate = new QgsComposerColumnAlignmentDelegate( mColumnsTableView );
mColumnsTableView->setItemDelegateForColumn( 2, mColumnAlignmentDelegate );
mColumnWidthDelegate = new QgsComposerColumnWidthDelegate( mColumnsTableView );
mColumnsTableView->setItemDelegateForColumn( 3, mColumnWidthDelegate );

mAvailableSortProxyModel = new QgsComposerTableSortColumnsProxyModelV2( mComposerTable, QgsComposerTableSortColumnsProxyModelV2::ShowUnsortedColumns, mSortColumnComboBox );
mAvailableSortProxyModel->setSourceModel( mColumnModel );
Expand Down Expand Up @@ -540,3 +589,4 @@ void QgsAttributeSelectionDialog::on_mSortColumnDownPushButton_clicked()
mColumnModelV1->moveColumnInSortRank( column, QgsComposerAttributeTableColumnModel::ShiftDown );
}
}

17 changes: 17 additions & 0 deletions src/app/composer/qgsattributeselectiondialog.h
Expand Up @@ -71,6 +71,22 @@ class QgsComposerColumnSourceDelegate : public QItemDelegate
QgsVectorLayer* mVectorLayer;
};

// QgsComposerColumnWidthDelegate

/**A delegate for showing column width as a spin box*/
class QgsComposerColumnWidthDelegate : public QItemDelegate
{
Q_OBJECT

public:
QgsComposerColumnWidthDelegate( QObject *parent = 0 );
QWidget *createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const;
void setEditorData( QWidget *editor, const QModelIndex &index ) const;
void setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const;
void updateEditorGeometry( QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index ) const;

};


// QgsComposerColumnSortOrderDelegate

Expand Down Expand Up @@ -133,6 +149,7 @@ class QgsAttributeSelectionDialog: public QDialog, private Ui::QgsAttributeSelec
QgsComposerColumnAlignmentDelegate *mColumnAlignmentDelegate;
QgsComposerColumnSourceDelegate *mColumnSourceDelegate;
QgsComposerColumnSortOrderDelegate *mColumnSortOrderDelegate;
QgsComposerColumnWidthDelegate *mColumnWidthDelegate;

};

Expand Down
22 changes: 20 additions & 2 deletions src/core/composer/qgscomposerattributetablemodelv2.cpp
Expand Up @@ -63,7 +63,7 @@ int QgsComposerAttributeTableColumnModelV2::rowCount( const QModelIndex &parent
int QgsComposerAttributeTableColumnModelV2::columnCount( const QModelIndex &parent ) const
{
Q_UNUSED( parent );
return 3;
return 4;
}

QVariant QgsComposerAttributeTableColumnModelV2::data( const QModelIndex &index, int role ) const
Expand Down Expand Up @@ -119,7 +119,18 @@ QVariant QgsComposerAttributeTableColumnModelV2::data( const QModelIndex &index,
return column->hAlignment();
}
}

case 3:
{
if ( role == Qt::DisplayRole )
{
return column->width() <= 0 ? tr( "Automatic" ) : QString( tr( "%1 mm" ) ).arg( column->width(), 0, 'f', 2 );
}
else
{
//edit role
return column->width();
}
}
default:
return QVariant();
}
Expand Down Expand Up @@ -152,6 +163,9 @@ QVariant QgsComposerAttributeTableColumnModelV2::headerData( int section, Qt::Or
case 2:
return QVariant( tr( "Alignment" ) );

case 3:
return QVariant( tr( "Width" ) );

default:
return QVariant();
}
Expand Down Expand Up @@ -201,6 +215,10 @@ bool QgsComposerAttributeTableColumnModelV2::setData( const QModelIndex& index,
column->setHAlignment(( Qt::AlignmentFlag )value.toInt() );
emit dataChanged( index, index );
return true;
case 3:
column->setWidth( value.toDouble( ) );
emit dataChanged( index, index );
return true;
default:
break;
}
Expand Down
7 changes: 6 additions & 1 deletion src/core/composer/qgscomposertablecolumn.cpp
Expand Up @@ -21,7 +21,8 @@ QgsComposerTableColumn::QgsComposerTableColumn() :
mBackgroundColor( Qt::transparent ),
mHAlignment( Qt::AlignLeft ),
mSortByRank( 0 ),
mSortOrder( Qt::AscendingOrder )
mSortOrder( Qt::AscendingOrder ),
mWidth( 0.0 )
{

}
Expand Down Expand Up @@ -49,6 +50,8 @@ bool QgsComposerTableColumn::writeXML( QDomElement& columnElem, QDomDocument& do
columnElem.setAttribute( "sortByRank", QString::number( mSortByRank ) );
columnElem.setAttribute( "sortOrder", QString::number( mSortOrder ) );

columnElem.setAttribute( "width", QString::number( mWidth ) );

return true;
}

Expand All @@ -59,6 +62,7 @@ bool QgsComposerTableColumn::readXML( const QDomElement& columnElem )
mAttribute = columnElem.attribute( "attribute", "" );
mSortByRank = columnElem.attribute( "sortByRank", "0" ).toInt();
mSortOrder = ( Qt::SortOrder )columnElem.attribute( "sortOrder", QString::number( Qt::AscendingOrder ) ).toInt();
mWidth = columnElem.attribute( "width", "0.0" ).toDouble();

QDomNodeList bgColorList = columnElem.elementsByTagName( "backgroundColor" );
if ( bgColorList.size() > 0 )
Expand Down Expand Up @@ -87,5 +91,6 @@ QgsComposerTableColumn* QgsComposerTableColumn::clone()
newColumn->setHAlignment( mHAlignment );
newColumn->setSortByRank( mSortByRank );
newColumn->setSortOrder( mSortOrder );
newColumn->setWidth( mWidth );
return newColumn;
}
15 changes: 15 additions & 0 deletions src/core/composer/qgscomposertablecolumn.h
Expand Up @@ -48,6 +48,20 @@ class CORE_EXPORT QgsComposerTableColumn: public QObject
*/
virtual bool readXML( const QDomElement& columnElem );

/**Returns the width for a column.
* @returns column width in mm, or 0 if column width is automatically calculated.
* @note added in 2.5
* @see setWidth
*/
double width() const { return mWidth; }

/**Sets the width for a column.
* @param width column width in mm, or 0 if column width is to be automatically calculated.
* @note added in 2.5
* @see width
*/
void setWidth( const double width ) { mWidth = width; }

/**Returns the heading for a column, which is the value displayed in the columns
* header cell.
* @returns Heading for column.
Expand Down Expand Up @@ -160,6 +174,7 @@ class CORE_EXPORT QgsComposerTableColumn: public QObject
QString mAttribute;
int mSortByRank;
Qt::SortOrder mSortOrder;
double mWidth;

};

Expand Down
31 changes: 25 additions & 6 deletions src/core/composer/qgscomposertablev2.cpp
Expand Up @@ -266,6 +266,15 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const
currentY = ( mShowGrid ? mGridStrokeWidth : 0 );
currentX += mCellMargin;

Qt::TextFlag textFlag = ( Qt::TextFlag )0;
if (( *columnIt )->width() <= 0 )
{
//automatic column width, so we use the Qt::TextDontClip flag when drawing contents, as this works nicer for italicised text
//which may slightly exceed the calculated width
//if column size was manually set then we do apply text clipping, to avoid painting text outside of columns width
textFlag = Qt::TextDontClip;
}

if ( drawHeader )
{
//draw the header
Expand All @@ -289,8 +298,7 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const
break;
}


QgsComposerUtils::drawText( p, cell, ( *columnIt )->heading(), mHeaderFont, mHeaderFontColor, headerAlign, Qt::AlignVCenter, Qt::TextDontClip );
QgsComposerUtils::drawText( p, cell, ( *columnIt )->heading(), mHeaderFont, mHeaderFontColor, headerAlign, Qt::AlignVCenter, textFlag );

currentY += cellHeaderHeight;
currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
Expand All @@ -303,7 +311,8 @@ void QgsComposerTableV2::render( QPainter *p, const QRectF &renderExtent, const

QVariant cellContents = mTableContents.at( row ).at( col );
QString str = cellContents.toString();
QgsComposerUtils::drawText( p, cell, str, mContentFont, mContentFontColor, ( *columnIt )->hAlignment(), Qt::AlignVCenter, Qt::TextDontClip );

QgsComposerUtils::drawText( p, cell, str, mContentFont, mContentFontColor, ( *columnIt )->hAlignment(), Qt::AlignVCenter, textFlag );

currentY += cellBodyHeight;
currentY += ( mShowGrid ? mGridStrokeWidth : 0 );
Expand Down Expand Up @@ -537,10 +546,16 @@ bool QgsComposerTableV2::calculateMaxColumnWidths()
for ( ; columnIt != mColumns.constEnd(); ++columnIt )
{
double width = 0;
if ( mHeaderMode != QgsComposerTableV2::NoHeaders )
if (( *columnIt )->width() > 0 )
{
//column has manually specified width
width = ( *columnIt )->width();
}
else if ( mHeaderMode != QgsComposerTableV2::NoHeaders )
{
width = QgsComposerUtils::textWidthMM( mHeaderFont, ( *columnIt )->heading() );
}

mMaxColumnWidthMap.insert( col, width );
col++;
}
Expand All @@ -554,8 +569,12 @@ bool QgsComposerTableV2::calculateMaxColumnWidths()
int columnNumber = 0;
for ( ; colIt != rowIt->constEnd(); ++colIt )
{
currentCellTextWidth = QgsComposerUtils::textWidthMM( mContentFont, ( *colIt ).toString() );
mMaxColumnWidthMap[ columnNumber ] = qMax( currentCellTextWidth, mMaxColumnWidthMap[ columnNumber ] );
if ( mColumns.at( columnNumber )->width() <= 0 )
{
//column width set to automatic, so check content size
currentCellTextWidth = QgsComposerUtils::textWidthMM( mContentFont, ( *colIt ).toString() );
mMaxColumnWidthMap[ columnNumber ] = qMax( currentCellTextWidth, mMaxColumnWidthMap[ columnNumber ] );
}
columnNumber++;
}
}
Expand Down
13 changes: 13 additions & 0 deletions tests/src/core/testqgscomposertablev2.cpp
Expand Up @@ -19,6 +19,7 @@
#include "qgscomposition.h"
#include "qgscomposermap.h"
#include "qgscomposerattributetablev2.h"
#include "qgscomposertablecolumn.h"
#include "qgscomposerframe.h"
#include "qgsmapsettings.h"
#include "qgsvectorlayer.h"
Expand Down Expand Up @@ -46,6 +47,8 @@ class TestQgsComposerTableV2: public QObject
void attributeTableVisibleOnly(); //test displaying only visible attributes
void attributeTableRender(); //test rendering attribute table

void manualColumnWidth(); //test setting manual column widths

void attributeTableExtend();
void attributeTableRepeat();

Expand Down Expand Up @@ -301,6 +304,16 @@ void TestQgsComposerTableV2::attributeTableRender()
QVERIFY( result );
}

void TestQgsComposerTableV2::manualColumnWidth()
{
mComposerAttributeTable->setMaximumNumberOfFeatures( 20 );
mComposerAttributeTable->columns()->at( 0 )->setWidth( 5 );
QgsCompositionChecker checker( "composerattributetable_columnwidth", mComposition );
bool result = checker.testComposition( mReport, 0 );
mComposerAttributeTable->columns()->at( 0 )->setWidth( 0 );
QVERIFY( result );
}

void TestQgsComposerTableV2::attributeTableExtend()
{
//test that adding and removing frames automatically does not result in a crash
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b893cb2

Please sign in to comment.