diff --git a/python/core/composer/qgscomposertablecolumn.sip b/python/core/composer/qgscomposertablecolumn.sip index e6e0a1e5d4d..8072c7337cc 100644 --- a/python/core/composer/qgscomposertablecolumn.sip +++ b/python/core/composer/qgscomposertablecolumn.sip @@ -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. diff --git a/src/app/composer/qgsattributeselectiondialog.cpp b/src/app/composer/qgsattributeselectiondialog.cpp index 0b9b20c3ea7..5ca11aa6e99 100644 --- a/src/app/composer/qgsattributeselectiondialog.cpp +++ b/src/app/composer/qgsattributeselectiondialog.cpp @@ -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( editor ); + spinBox->setValue( value ); +} + +void QgsComposerColumnWidthDelegate::setModelData( QWidget *editor, QAbstractItemModel *model, const QModelIndex &index ) const +{ + QDoubleSpinBox *spinBox = static_cast( 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 @@ -232,7 +278,8 @@ QgsAttributeSelectionDialog::QgsAttributeSelectionDialog( QgsComposerAttributeTa mAvailableSortProxyModel( 0 ), mAvailableSortProxyModelV1( 0 ), mColumnAlignmentDelegate( 0 ), - mColumnSortOrderDelegate( 0 ) + mColumnSortOrderDelegate( 0 ), + mColumnWidthDelegate( 0 ) { setupUi( this ); @@ -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 ); @@ -540,3 +589,4 @@ void QgsAttributeSelectionDialog::on_mSortColumnDownPushButton_clicked() mColumnModelV1->moveColumnInSortRank( column, QgsComposerAttributeTableColumnModel::ShiftDown ); } } + diff --git a/src/app/composer/qgsattributeselectiondialog.h b/src/app/composer/qgsattributeselectiondialog.h index 6aad0d96d34..bd78090b67d 100644 --- a/src/app/composer/qgsattributeselectiondialog.h +++ b/src/app/composer/qgsattributeselectiondialog.h @@ -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 @@ -133,6 +149,7 @@ class QgsAttributeSelectionDialog: public QDialog, private Ui::QgsAttributeSelec QgsComposerColumnAlignmentDelegate *mColumnAlignmentDelegate; QgsComposerColumnSourceDelegate *mColumnSourceDelegate; QgsComposerColumnSortOrderDelegate *mColumnSortOrderDelegate; + QgsComposerColumnWidthDelegate *mColumnWidthDelegate; }; diff --git a/src/core/composer/qgscomposerattributetablemodelv2.cpp b/src/core/composer/qgscomposerattributetablemodelv2.cpp index f22e644341e..77fede21759 100644 --- a/src/core/composer/qgscomposerattributetablemodelv2.cpp +++ b/src/core/composer/qgscomposerattributetablemodelv2.cpp @@ -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 @@ -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(); } @@ -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(); } @@ -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; } diff --git a/src/core/composer/qgscomposertablecolumn.cpp b/src/core/composer/qgscomposertablecolumn.cpp index b926fc20197..b16b5044d6d 100644 --- a/src/core/composer/qgscomposertablecolumn.cpp +++ b/src/core/composer/qgscomposertablecolumn.cpp @@ -21,7 +21,8 @@ QgsComposerTableColumn::QgsComposerTableColumn() : mBackgroundColor( Qt::transparent ), mHAlignment( Qt::AlignLeft ), mSortByRank( 0 ), - mSortOrder( Qt::AscendingOrder ) + mSortOrder( Qt::AscendingOrder ), + mWidth( 0.0 ) { } @@ -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; } @@ -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 ) @@ -87,5 +91,6 @@ QgsComposerTableColumn* QgsComposerTableColumn::clone() newColumn->setHAlignment( mHAlignment ); newColumn->setSortByRank( mSortByRank ); newColumn->setSortOrder( mSortOrder ); + newColumn->setWidth( mWidth ); return newColumn; } diff --git a/src/core/composer/qgscomposertablecolumn.h b/src/core/composer/qgscomposertablecolumn.h index 8e61f89a23f..76ab6b437c7 100644 --- a/src/core/composer/qgscomposertablecolumn.h +++ b/src/core/composer/qgscomposertablecolumn.h @@ -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. @@ -160,6 +174,7 @@ class CORE_EXPORT QgsComposerTableColumn: public QObject QString mAttribute; int mSortByRank; Qt::SortOrder mSortOrder; + double mWidth; }; diff --git a/src/core/composer/qgscomposertablev2.cpp b/src/core/composer/qgscomposertablev2.cpp index 94d8dcf0855..3b817e62cbb 100644 --- a/src/core/composer/qgscomposertablev2.cpp +++ b/src/core/composer/qgscomposertablev2.cpp @@ -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 @@ -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 ); @@ -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 ); @@ -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++; } @@ -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++; } } diff --git a/tests/src/core/testqgscomposertablev2.cpp b/tests/src/core/testqgscomposertablev2.cpp index 78dbe197ad0..e613dba82d3 100644 --- a/tests/src/core/testqgscomposertablev2.cpp +++ b/tests/src/core/testqgscomposertablev2.cpp @@ -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" @@ -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(); @@ -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 diff --git a/tests/testdata/control_images/expected_composerattributetable_columnwidth/expected_composerattributetable_columnwidth.png b/tests/testdata/control_images/expected_composerattributetable_columnwidth/expected_composerattributetable_columnwidth.png new file mode 100644 index 00000000000..6872118b7df Binary files /dev/null and b/tests/testdata/control_images/expected_composerattributetable_columnwidth/expected_composerattributetable_columnwidth.png differ