diff options
author | Thomas Zander <thomas.zander@trolltech.com> | 2009-05-20 14:03:50 +0200 |
---|---|---|
committer | Thomas Zander <thomas.zander@trolltech.com> | 2009-05-20 14:03:50 +0200 |
commit | 607f18a8763c77b56bd22d10cb922abf1c81d3d0 (patch) | |
tree | 3e38d69788f5c772d5adf30ef5f1514e6b74b15c /src | |
parent | 04a790f42a8ae3b7ac540fc4ac89055e6acba953 (diff) | |
parent | 012bcd27dd0783721f89e81dc40d0847bb27b360 (diff) |
Merge branch 'tableItemLayout'
Diffstat (limited to 'src')
-rw-r--r-- | src/qgraphicsheader.cpp | 16 | ||||
-rw-r--r-- | src/qgraphicsheader.h | 2 | ||||
-rw-r--r-- | src/qgraphicstableview.cpp | 301 | ||||
-rw-r--r-- | src/qgraphicstableview.h | 22 | ||||
-rw-r--r-- | src/qgraphicstableview_p.h | 11 | ||||
-rw-r--r-- | src/qprintertableview.cpp | 344 | ||||
-rw-r--r-- | src/qprintertableview.h | 74 | ||||
-rw-r--r-- | src/qprintertableview_p.h | 77 | ||||
-rw-r--r-- | src/qtablecontroller.cpp | 63 | ||||
-rw-r--r-- | src/src.pro | 3 |
10 files changed, 768 insertions, 145 deletions
diff --git a/src/qgraphicsheader.cpp b/src/qgraphicsheader.cpp index 6f1ea03..0d1cc38 100644 --- a/src/qgraphicsheader.cpp +++ b/src/qgraphicsheader.cpp @@ -1420,9 +1420,7 @@ void QtGraphicsHeader::initStyleOption(QStyleOptionHeader *option, int logicalIn option->section = logicalIndex; - const int visual = d->logicalToVisual.isEmpty() - ? logicalIndex - : d->logicalToVisual.at(logicalIndex); + const int visual = d->logicalToVisual.value(logicalIndex, logicalIndex); if (d->sectionCount == 1) option->position = QStyleOptionHeader::OnlyOneSection; @@ -1552,4 +1550,16 @@ void QtGraphicsHeader::copyStyleOptionState(const QStyleOptionGraphicsItem *sour } } +void QtGraphicsHeader::setSectionsState(const QtGraphicsHeader &other) +{ + Q_D(QtGraphicsHeader); + d->cachedDataIndex = -1; + setSectionCount(other.sectionCount()); + d->sectionSizeSpans = other.d_ptr->sectionSizeSpans; + d->sectionModeSpans = other.d_ptr->sectionModeSpans; + d->sectionMovableSpans = other.d_ptr->sectionMovableSpans; + d->sectionClickableSpans = other.d_ptr->sectionClickableSpans; + d->sectionSelectedSpans = other.d_ptr->sectionSelectedSpans; +} + #include "moc_qgraphicsheader.cpp" diff --git a/src/qgraphicsheader.h b/src/qgraphicsheader.h index 694d6d6..cd0997e 100644 --- a/src/qgraphicsheader.h +++ b/src/qgraphicsheader.h @@ -105,6 +105,8 @@ public: //virtual void autoResizeSections(); void copyStyleOptionState(const QStyleOptionGraphicsItem *source, QStyleOptionHeader *dest); + void setSectionsState(const QtGraphicsHeader &other); + public Q_SLOTS: void setOffset(qreal offset); void setSectionCount(int count); diff --git a/src/qgraphicstableview.cpp b/src/qgraphicstableview.cpp index 195879a..f971c18 100644 --- a/src/qgraphicstableview.cpp +++ b/src/qgraphicstableview.cpp @@ -39,16 +39,6 @@ #include <qgraphicssceneevent.h> -// QtTableOption - -QtTableOption::QtTableOption(const QStyleOptionGraphicsItem *option) - : graphicsOption(option), - flags(0), - firstRow(0), - firstColumn(0) -{ -} - // QtGraphicsTableViewItem QtGraphicsTableViewItem::QtGraphicsTableViewItem(int row, int column, QtGraphicsTableView *view) @@ -103,6 +93,7 @@ QSizeF QtGraphicsTableViewItem::sizeHint(int row, int column, const QStyleOption Q_D(const QtGraphicsTableViewItem); switch (which) { case Qt::MinimumSize: + return QSizeF(1, 1); case Qt::PreferredSize: { const QVariant value = d->view->d_func()->cachedData(row, column, Qt::SizeHintRole); if (value.isValid()) @@ -140,21 +131,13 @@ QtGraphicsTableView *QtGraphicsTableViewItem::view() const return d->view; } - -/*QRectF QtGraphicsTableViewItem::boundingRect() const -{ - Q_D(const QtGraphicsTableViewItem); - return QRectF(QPointF(0, 0), d->view->cellSize(d->row, d->column)); -} -*/ - void QtGraphicsTableViewItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(widget); Q_D(QtGraphicsTableViewItem); d->view->initStyleOption(&d->option); d->view->initStyleOption(&d->option, d->row, d->column); - d->option.rect = QRect(QPoint(0, 0), d->view->cellSize(d->row, d->column).toSize()); + d->option.rect = QRectF(QPointF(), size()).toRect(); d->view->copyStyleOptionState(option, &d->option); //style()->drawControl(QStyle::CE_ItemViewItem, &d->option, painter, widget); d->view->paintCell(painter, &d->option, d->row, d->column); @@ -332,6 +315,108 @@ QVariant QtGraphicsTableViewPrivate::cachedData(int row, int column, int role) c return cachedDataHash.value(role); } +QtGraphicsTableViewItem *QtGraphicsTableViewPrivate::item(int row, int column) const +{ + if (! childItemIndexes.contains(row)) + return 0; + for (int index = childItemIndexes.value(row); index < childItems.size(); ++index) { + QtGraphicsTableViewItem *item = childItems.value(index); + if (item == 0) + continue; + if (item->row() != row) + break; + else if (item->column() == column) + return item; + } + return 0; +} + +void QtGraphicsTableViewPrivate::setItem(QtGraphicsTableViewItem *newItem) +{ + const int row = newItem->row(); + if (! childItemIndexes.contains(row)) { // thats easy + childItemIndexes.insert(row, childItems.count()); + childItems.append(newItem); + return; + } + int index; + for (index = childItemIndexes.value(row); index < childItems.size(); ++index) { + QtGraphicsTableViewItem *item = childItems.value(index); + if (item == 0) { // yeah, fill a gap! + childItems.replace(index, newItem); + return; + } + if (item->row() != row) + break; // found insertion spot + } + + childItems.insert(index, newItem); + if (index == childItems.size()-1) // we appended + return; + QHash<int,int> oldIndexes = childItemIndexes; + childItemIndexes.clear(); + QHash<int,int>::ConstIterator iter = oldIndexes.constBegin(); + while (iter != oldIndexes.constEnd()) { + if (iter.value() < index) + childItemIndexes.insert(iter.key(), iter.value()); + else + childItemIndexes.insert(iter.key(), iter.value() + 1); + ++iter; + } +} + +void QtGraphicsTableViewPrivate::removeItemsOnRow(int row) +{ + Q_ASSERT(childItemIndexes.contains(row)); + + int index = childItemIndexes.value(row); + childItemIndexes.remove(row); + do { + QtGraphicsTableViewItem *item = childItems.value(index); + if (item) { + if (item->row() != row) // done! + return; + childItems.replace(index, 0); + unusedItems.append(item); + item->hide(); + } + ++index; + } while (index < childItems.size()); +} + +void QtGraphicsTableViewPrivate::removeItem(int row, int column) +{ + if (! childItemIndexes.contains(row)) + return; + for (int index = childItemIndexes.value(row); index < childItems.size(); ++index) { + QtGraphicsTableViewItem *item = childItems.value(index); + if (item == 0) + continue; + if (item->column() == column) { + childItems.replace(index, 0); + unusedItems.append(item); + item->hide(); + return; + } + else if (item->column() > column || item->row() != row) + break; + } +} + +void QtGraphicsTableViewPrivate::recycleUnusedItems(const QSet<QtGraphicsTableViewItem*> &usedItems) +{ + for (int index = 0; index < childItems.count(); ++index) { + QtGraphicsTableViewItem *item = childItems.value(index); + if (item == 0) + continue; + if (! usedItems.contains(item)) { + childItems.replace(index, 0); + unusedItems.append(item); + item->hide(); + } + } +} + // QtGraphicsTableView /*! @@ -347,8 +432,6 @@ QtGraphicsTableView::QtGraphicsTableView(QGraphicsWidget *parent, Qt::WindowFlag : QGraphicsWidget(parent, wFlags), d_ptr(new QtGraphicsTableViewPrivate) { d_ptr->q_ptr = this; - setHorizontalHeader(new QtGraphicsHeader(Qt::Horizontal)); - setVerticalHeader(new QtGraphicsHeader(Qt::Vertical)); } /*! @@ -390,6 +473,7 @@ void QtGraphicsTableView::setController(QtTableController *controller) QObject::connect(d->controller, SIGNAL(destroyed()), this, SLOT(_q_controllerDestroyed())); } + updateLayout(); } /*! @@ -444,6 +528,7 @@ void QtGraphicsTableView::setModel(QtTableModelInterface *model) QObject::connect(d->model, SIGNAL(columnsMoved(int,int,int)), this, SLOT(_q_columnsMoved(int,int,int))); } + updateLayout(); } /*! @@ -496,6 +581,7 @@ void QtGraphicsTableView::setVerticalHeader(QtGraphicsHeader *header) connect(d->verticalHeader, SIGNAL(destroyed()), this, SLOT(_q_verticalHeaderDestroyed())); } + updateLayout(); } QtGraphicsHeader *QtGraphicsTableView::verticalHeader() const @@ -520,6 +606,7 @@ void QtGraphicsTableView::setHorizontalHeader(QtGraphicsHeader *header) connect(d->horizontalHeader, SIGNAL(destroyed()), this, SLOT(_q_horizontalHeaderDestroyed())); } + updateLayout(); } QtGraphicsHeader *QtGraphicsTableView::horizontalHeader() const @@ -535,6 +622,7 @@ void QtGraphicsTableView::setTextElideMode(Qt::TextElideMode mode) Q_D(QtGraphicsTableView); d->textElideMode = mode; + updateLayout(); } /*! @@ -562,6 +650,7 @@ void QtGraphicsTableView::setRowHeight(int row, qreal height) Q_D(QtGraphicsTableView); if (d->verticalHeader) d->verticalHeader->setSectionSize(row, height); + updateLayout(); } /*! @@ -580,6 +669,7 @@ void QtGraphicsTableView::setColumnWidth(int column, qreal width) Q_D(QtGraphicsTableView); if (d->horizontalHeader) d->horizontalHeader->setSectionSize(column, width); + updateLayout(); } /*! @@ -604,6 +694,7 @@ void QtGraphicsTableView::setRowHidden(int row, bool hide) Q_D(QtGraphicsTableView); if (d->verticalHeader) d->verticalHeader->setSectionHidden(row, hide); + updateLayout(); } /*! @@ -621,6 +712,7 @@ void QtGraphicsTableView::setColumnHidden(int column, bool hide) Q_D(QtGraphicsTableView); if (d->horizontalHeader) d->horizontalHeader->setSectionHidden(column, hide); + updateLayout(); } /*! @@ -745,6 +837,7 @@ void QtGraphicsTableView::setFirstRow(int row) if (d->verticalHeader) d->verticalHeader->setFirstSection(row); d->firstRow = row; + updateLayout(); } /*! @@ -763,6 +856,7 @@ void QtGraphicsTableView::setFirstColumn(int column) if (d->horizontalHeader) d->horizontalHeader->setFirstSection(column); d->firstColumn = column; + updateLayout(); } /*! @@ -781,6 +875,7 @@ void QtGraphicsTableView::setHorizontalOffset(qreal offset) if (d->horizontalHeader) d->horizontalHeader->setOffset(offset); d->horizontalOffset = offset; + updateLayout(); } /*! @@ -799,6 +894,7 @@ void QtGraphicsTableView::setVerticalOffset(qreal offset) if (d->verticalHeader) d->verticalHeader->setOffset(offset); d->verticalOffset = offset; + updateLayout(); } /*! @@ -903,77 +999,59 @@ bool QtGraphicsTableView::showGrid() const /*! Paints the table using the given \a painter */ -void QtGraphicsTableView::paint(QPainter *painter, const QStyleOptionGraphicsItem *graphicsOption, QWidget *widget) -{ - Q_UNUSED(widget); - Q_D(const QtGraphicsTableView); - QtTableOption option(graphicsOption); - option.flags = PaintGrid; - option.flags |= PaintBackground; - - if (d->horizontalHeader) - option.firstColumn = d->horizontalHeader->firstSection(); - else if (d->model) - option.firstColumn = d->firstColumn; - - if (d->verticalHeader) - option.firstRow = d->verticalHeader->firstSection(); - else if (d->model) - option.firstRow = d->firstRow; - - if (graphicsOption) { - //painter->translate(graphicsOption->exposedRect.topLeft()); - option.section = graphicsOption->exposedRect; - } else { - option.section = QRectF(QPointF(), size()); - } - - //painter->setClipRect(0, 0, option.section.width(), option.section.height()); - paintSection(painter, &option); -} -/*! - Paints the table using the given \a painter - */ -void QtGraphicsTableView::paintSection(QPainter *painter, const QtTableOption *tableOption) +void QtGraphicsTableView::paint(QPainter *painter, const QStyleOptionGraphicsItem *graphicsOption, QWidget *widget) { Q_D(const QtGraphicsTableView); - Q_ASSERT(tableOption); + Q_UNUSED(widget); int verticalCount = 0; int horizontalCount = 0; qreal verticalOffset = 0; qreal horizontalOffset = 0; QVector<int> verticalMapping; QVector<int> horizontalMapping; - const QStyleOptionGraphicsItem *graphicsOption = tableOption->graphicsOption; - QRectF area = tableOption->section; + QRectF area; + if (graphicsOption) { + area = graphicsOption->exposedRect; + } else if (painter->hasClipping()) { + area = painter->clipRegion().boundingRect(); + } else { + area = QRectF(QPoint(), size()); + } + + int firstRow = 0; + int firstColumn = 0; if (d->horizontalHeader) { horizontalCount = d->horizontalHeader->sectionCount(); horizontalOffset = d->horizontalHeader->offset(); horizontalMapping = d->horizontalHeader->indexMapping(); + firstColumn = d->horizontalHeader->firstSection(); } else if (d->model) { horizontalCount = d->model->columnCount(); horizontalOffset = d->horizontalOffset; + firstColumn = d->firstColumn; } if (d->verticalHeader) { verticalCount = d->verticalHeader->sectionCount(); verticalOffset = d->verticalHeader->offset(); verticalMapping = d->verticalHeader->indexMapping(); + firstRow = d->verticalHeader->firstSection(); } else if (d->model) { verticalCount = d->model->rowCount(); verticalOffset = d->verticalOffset; + firstRow = d->firstRow; } + // paint the contents int row; int column; - int vertical = tableOption->firstRow; int horizontal; + int vertical = firstRow; qreal rowHeight; qreal columnWidth; qreal x; qreal y = 0; QStyleOptionViewItemV4 option; - initStyleOption(&option); copyStyleOptionState(graphicsOption, &option); // set the grid option QColor gridColor = static_cast<QRgb>(style()->styleHint(QStyle::SH_Table_GridLineColor, &option, option.widget)); @@ -985,22 +1063,14 @@ void QtGraphicsTableView::paintSection(QPainter *painter, const QtTableOption *t rowHeight = d->verticalHeader ? d->verticalHeader->sectionSize(row) : d->defaultRowHeight; if (y >= area.top()) { x = 0; - horizontal = tableOption->firstColumn; + horizontal = firstColumn; while (x < area.width() && horizontal < horizontalCount) { column = horizontalMapping.value(horizontal, horizontal); columnWidth = d->horizontalHeader ? d->horizontalHeader->sectionSize(column) : d->defaultColumnWidth; if (x >= area.left()) { - initStyleOption(&option, row, column); QRectF rect(x, y, columnWidth - gridSize, rowHeight - gridSize); - option.rect = rect.toRect(); - if ((tableOption->flags & PaintBackground) == 0) - option.backgroundBrush = QBrush(Qt::NoBrush); - //if (cellEditor(row, column)) - // paintCellEditor(painter, &option, row, column); - //else - paintCell(painter, &option, row, column); // draw grid - if (d->showGrid && (tableOption->flags & PaintGrid)) { + if (d->showGrid) { QPen pen = painter->pen(); painter->setPen(gridPen); painter->drawLine(int(rect.left()), int(rect.bottom()), int(rect.right()), int(rect.bottom())); @@ -1156,9 +1226,8 @@ void QtGraphicsTableView::initStyleOption(QStyleOptionViewItemV4 *option, int ro break; default: { QString text = value.toString(); - const QChar nl = QLatin1Char('\n'); for (int i = 0; i < text.count(); ++i) - if (text.at(i) == nl) + if (text.at(i).unicode() == '\n') text[i] = QChar::LineSeparator; option->text = text; break; } @@ -1218,4 +1287,96 @@ bool QtGraphicsTableView::event(QEvent *event) return QObject::event(event); } +void QtGraphicsTableView::updateLayout() +{ + doLayout(); /// we likely want to use a singleShot instead +} + +void QtGraphicsTableView::doLayout() +{ + Q_D(QtGraphicsTableView); + if (d->model == 0) + return; + + QVector<int> verticalMapping; + QVector<int> horizontalMapping; + int maxColumn, maxRow; + qreal horizontalOffset, verticalOffset; + if (d->horizontalHeader) { + maxColumn = d->horizontalHeader->sectionCount() - 1; + horizontalOffset = d->horizontalHeader->offset(); + horizontalMapping = d->horizontalHeader->indexMapping(); + if (!horizontalMapping.isEmpty()) + maxColumn = qMin(maxColumn, horizontalMapping.size() - 1); + } else { + maxColumn = d->model->columnCount() - 1; + horizontalOffset = d->horizontalOffset; + } + if (d->verticalHeader) { + maxRow = d->verticalHeader->sectionCount() - 1; + verticalOffset = d->verticalHeader->offset(); + verticalMapping = d->verticalHeader->indexMapping(); + if (!verticalMapping.isEmpty()) + maxRow = qMin(maxRow, verticalMapping.size() - 1); + } else { + maxRow = d->model->rowCount() - 1; + verticalOffset = d->verticalOffset; + } + + qreal x; + qreal y = verticalOffset; + QSet<QtGraphicsTableViewItem*> itemsVisualized;// tracks all items we show allowing us to recycle all the rest. + for (int visualRow = d->firstRow; visualRow <= maxRow; ++visualRow) { + x = -horizontalOffset; + const int effectiveRow = verticalMapping.value(visualRow, visualRow); + const qreal height = rowHeight(effectiveRow); + QtGraphicsTableViewItem *item = 0; + for (int visualColumn = d->firstColumn; visualColumn <= maxColumn; ++visualColumn) { + const int effectiveColumn = horizontalMapping.value(visualColumn, visualColumn); + + const qreal width = columnWidth(effectiveColumn); + if (d->cachedData(effectiveRow, effectiveColumn, QtTableModelInterface::TextRole).isNull() + // ### should we check for more data to determine the cell is empty? + && d->cachedData(effectiveRow, effectiveColumn, QtTableModelInterface::IconRole).isNull()) { + + // No data, maybe make the previous item wider. + if (item) { + const qreal prefWidth = item->sizeHint(Qt::PreferredSize).width(); + if (prefWidth > item->size().width()) { + item->resize(qMin(item->size().width() + width, prefWidth), height); + } + } + d->removeItem(effectiveRow, effectiveColumn); + x += width; + if (x > size().width()) + break; + continue; + } + item = d->item(effectiveRow, effectiveColumn); + + if (item == 0) { + if (d->unusedItems.isEmpty()) { + item = new QtGraphicsTableViewItem(effectiveRow, effectiveColumn, this); + } else { + item = d->unusedItems.takeLast(); + item->setIndex(effectiveRow, effectiveColumn); + item->show(); + } + d->setItem(item); + } + Q_ASSERT(item); + itemsVisualized << item; + item->setGeometry(x, y, width, height); + x += width; + if (x > size().width()) + break; + } + y += height; + if (y > size().height()) // no more visible space + break; + } + + d->recycleUnusedItems(itemsVisualized); +} + #include "moc_qgraphicstableview.cpp" diff --git a/src/qgraphicstableview.h b/src/qgraphicstableview.h index 4a39f32..2a9e03e 100644 --- a/src/qgraphicstableview.h +++ b/src/qgraphicstableview.h @@ -61,12 +61,6 @@ class Q_ITEMVIEWSNG_EXPORT QtGraphicsTableView : public QGraphicsWidget Q_PROPERTY(QtGraphicsHeader* verticalHeader READ verticalHeader WRITE setVerticalHeader) public: - enum PaintingFlag { - PaintGrid = 0x00000001, - PaintBackground = 0x00000002 - }; - Q_DECLARE_FLAGS(PaintingFlags, PaintingFlag) - explicit QtGraphicsTableView(QGraphicsWidget *parent = 0, Qt::WindowFlags wFlags = 0); virtual ~QtGraphicsTableView(); @@ -127,6 +121,8 @@ public: bool showGrid() const; + virtual void doLayout(); + public: virtual int rowAt(const QPointF &position, const QTransform &transform = QTransform()) const; virtual int columnAt(const QPointF &position, const QTransform &transform = QTransform()) const; @@ -146,6 +142,7 @@ public Q_SLOTS: void setHorizontalOffset(qreal offset); void setVerticalOffset(qreal offset); void setShowGrid(bool on); + void updateLayout(); Q_SIGNALS: void firstRowChanged(int row); @@ -159,6 +156,7 @@ protected: QtGraphicsTableView(QtGraphicsTableViewPrivate&, QGraphicsWidget *parent = 0, Qt::WindowFlags wFlags = 0); virtual bool event(QEvent *event); + friend class QtPrinterTableView; // ### FIXME: should not be needed friend class QtTableController; void setModel(QtTableModelInterface *model); void setSelectionManager(QtTableSelectionManager *selectionManager); @@ -215,18 +213,6 @@ private: Q_DECLARE_PRIVATE(QtGraphicsTableViewItem) }; -class Q_ITEMVIEWSNG_EXPORT QtTableOption -{ -public: - QtTableOption(const QStyleOptionGraphicsItem *graphicsOption = 0); - - const QStyleOptionGraphicsItem * const graphicsOption; - QtGraphicsTableView::PaintingFlags flags; - int firstRow; - int firstColumn; - QRectF section; -}; - QT_END_NAMESPACE QT_END_HEADER diff --git a/src/qgraphicstableview_p.h b/src/qgraphicstableview_p.h index 7e2fbec..3240070 100644 --- a/src/qgraphicstableview_p.h +++ b/src/qgraphicstableview_p.h @@ -114,6 +114,17 @@ public: mutable int cachedDataColumn; QtGraphicsTableView *q_ptr; + + QtGraphicsTableViewItem *item(int row, int column) const; + void setItem(QtGraphicsTableViewItem *item); + void removeItemsOnRow(int row); // ### unused + void removeItem(int row, int column); + void recycleUnusedItems(const QSet<QtGraphicsTableViewItem*> &usedItems); + +private: + QList<QtGraphicsTableViewItem*> childItems; + QList<QtGraphicsTableViewItem*> unusedItems; + QHash<int, int> childItemIndexes; // row to childItemIndexes.index mapping }; QT_END_NAMESPACE diff --git a/src/qprintertableview.cpp b/src/qprintertableview.cpp new file mode 100644 index 0000000..39bb674 --- /dev/null +++ b/src/qprintertableview.cpp @@ -0,0 +1,344 @@ +/**************************************************************************** +** +** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Itemviews NG project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 or 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#include "qprintertableview.h" +#include "qprintertableview_p.h" + +#ifndef QT_NO_PRINTER + +#include "qgraphicstableview.h" +#include "qtablemodelinterface.h" +#include "qgraphicsheader.h" + +#include <qgraphicsscene.h> +#include <qpainter.h> +#include <qtextdocument.h> +#include <qabstracttextdocumentlayout.h> +#include <qdebug.h> + +// #define DEBUG_TABLES + +QtPrinterTableViewPrivate::QtPrinterTableViewPrivate(QPrinter *p) + : q_ptr(0), + ownsPrinter(p == 0), + printer(ownsPrinter ? new QPrinter : p), + model(0), + orientation(Qt::Vertical), + header(0), + footer(0) +{ + headerFooterSpacing = 5; // in mm +} + +QtPrinterTableViewPrivate::~QtPrinterTableViewPrivate() +{ + delete header; + delete footer; + if (ownsPrinter) + delete printer; +} + +qreal QtPrinterTableViewPrivate::printHeader(QPainter &painter) +{ + if (header == 0) + return 0; + header->drawContents(&painter); + return header->size().height() + headerFooterSpacingInPixels(); +} + +qreal QtPrinterTableViewPrivate::printFooter(QPainter &painter) +{ + if (footer == 0) + return 0; + qreal pageHeight = printer->pageRect().height(); + const qreal footerSize = footer->size().height(); + painter.translate(0, pageHeight - footerSize); + footer->drawContents(&painter); + painter.translate(0, - (pageHeight - footerSize)); + return footerSize + headerFooterSpacingInPixels(); +} + +QTextDocument *QtPrinterTableViewPrivate::getOrCreateHeader() const +{ + if (header == 0) { + header = new QTextDocument(); + header->setUndoRedoEnabled(false); + header->setDocumentMargin(0); + } + return header; +} + +QTextDocument *QtPrinterTableViewPrivate::getOrCreateFooter() const +{ + if (footer == 0) { + footer = new QTextDocument(); + footer->setUndoRedoEnabled(false); + footer->setDocumentMargin(0); + } + return footer; +} + +/*! + \class QtPrinterTableView + \brief QtPrinterTableView allows you to print a table model. +*/ + +QtPrinterTableView::QtPrinterTableView(QtTableModelInterface *model, QtGraphicsHeader *verticalHeader, QtGraphicsHeader *horizontalHeader) + : d_ptr(new QtPrinterTableViewPrivate(0)) +{ + Q_ASSERT(model); + d_ptr->q_ptr = this; + d_ptr->model = model; + d_ptr->horizontalHeader = horizontalHeader; + d_ptr->verticalHeader = verticalHeader; +} + +QtPrinterTableView::QtPrinterTableView(QPrinter *printer, QtTableModelInterface *model, QtGraphicsHeader *verticalHeader, QtGraphicsHeader *horizontalHeader) + : d_ptr(new QtPrinterTableViewPrivate(printer)) +{ + Q_ASSERT(model); + d_ptr->q_ptr = this; + d_ptr->model = model; + d_ptr->horizontalHeader = horizontalHeader; + d_ptr->verticalHeader = verticalHeader; +} + +QtPrinterTableView::~QtPrinterTableView() +{ + delete d_ptr; +} + +QPrinter *QtPrinterTableView::printer() +{ + Q_D(QtPrinterTableView); + return d->printer; +} + +void QtPrinterTableView::setOrientation(Qt::Orientation orientation) +{ + Q_D(QtPrinterTableView); + d->orientation = orientation; +} + +Qt::Orientation QtPrinterTableView::orientation() const +{ + Q_D(const QtPrinterTableView); + return d->orientation; +} + +QTextDocument *QtPrinterTableView::headerDocument() +{ + Q_D(QtPrinterTableView); + return d->getOrCreateHeader(); +} + +QTextDocument *QtPrinterTableView::footerDocument() +{ + Q_D(QtPrinterTableView); + return d->getOrCreateFooter(); +} + +void QtPrinterTableView::setHeaderText(const QString &header) +{ + Q_D(QtPrinterTableView); + d->getOrCreateHeader()->setPlainText(header); +} + +void QtPrinterTableView::setFooterText(const QString &footer) +{ + Q_D(QtPrinterTableView); + d->getOrCreateFooter()->setPlainText(footer); +} + +QString QtPrinterTableView::headerText() const +{ + Q_D(const QtPrinterTableView); + return d->getOrCreateHeader()->toPlainText(); +} + +QString QtPrinterTableView::footerText() const +{ + Q_D(const QtPrinterTableView); + if (d->footer == 0) + return QString(); + return d->footer->toPlainText(); +} + +extern int qt_defaultDpiY(); +extern int qt_defaultDpiX(); + +bool QtPrinterTableView::print() +{ + Q_D(QtPrinterTableView); + if (! d->printer->isValid()) { + qWarning() << "QtPrinterTableView::print: printer not valid, please setup the printer before calling print"; + return false; + } + + // next use a view just for the filling of the options... + QGraphicsScene scene; + QtGraphicsTableView view; + scene.addItem(&view); + view.setModel(d->model); + + + class QTableHeaderDataProvider2 : public QtGraphicsHeaderDataProvider + { + public: + QTableHeaderDataProvider2(QtTableModelInterface *model_) : model(model_) {} + QHash<int,QVariant> data(int logicalIndex, const QList<int> &roles) const + { + // ### call the model - temporary implementation + QHash<int,QVariant> hash; + for (int i = 0; i < roles.count(); ++i) + if (roles.at(i) == Qt::DisplayRole) + hash.insert(Qt::DisplayRole, logicalIndex + 1); + return hash; + } + QtTableModelInterface *model; + }; + + if (d->horizontalHeader) { + QtGraphicsHeader *header = new QtGraphicsHeader(Qt::Horizontal, &view); + header->setDataProvider(new QTableHeaderDataProvider2(d->model)); + header->setSectionsState(*d->horizontalHeader); + view.setHorizontalHeader(header); + } + if (d->verticalHeader) { + QtGraphicsHeader *header = new QtGraphicsHeader(Qt::Vertical, &view); + header->setDataProvider(new QTableHeaderDataProvider2(d->model)); + header->setSectionsState(*d->verticalHeader); + view.setVerticalHeader(header); + } + + QPainter painter; + if (!painter.begin(d->printer)) { + qWarning() << "QtPrinterTableView::print: printer fails to begin(), sorry can't print"; + return false; + } + + // re-layout the header footer to the current page size. + if (d->header) { + d->header->documentLayout()->setPaintDevice(d->printer); + d->header->setPageSize(d->printer->pageRect().size()); + } + if (d->footer) { + d->footer->documentLayout()->setPaintDevice(d->printer); + d->footer->setPageSize(d->printer->pageRect().size()); + } + + const qreal headerSize = d->printHeader(painter); // TODO + const qreal footerSize = d->printFooter(painter); // TODO + const bool vertical = d->orientation == Qt::Vertical; // TODO + const qreal scaleX = d->printer->logicalDpiX() / (qreal) qt_defaultDpiX(); + const qreal scaleY = d->printer->logicalDpiY() / (qreal) qt_defaultDpiY(); + painter.scale(scaleX, scaleY); + + const QRect rect = d->printer->pageRect(); + const QSizeF visibleSize(rect.width() / scaleX, rect.height() / scaleY); + + view.setGeometry(0, 0, visibleSize.width(), visibleSize.height()); + view.setHorizontalOffset(0); + + int row = 0; + int column; + bool first = true; + qreal offsetInColumn = 0; // for those columns too wide and thus split over more than one page + while (row < d->model->rowCount()) { + column = 0; + view.setFirstRow(row); + qreal height = visibleSize.height(); + while (true) { + const qreal rowHeight = view.rowHeight(row); + if (height - rowHeight < 0) + break; + if (row >= d->model->rowCount()) + break; + ++row; + height -= rowHeight; + } + while (column < d->model->columnCount()) { + if (!first) + d->printer->newPage(); + first = false; + view.setFirstColumn(column); + view.setHorizontalOffset(offsetInColumn); + + qreal width = visibleSize.width(); + while (true) { + const qreal columnWidth = view.columnWidth(column); + if (width == visibleSize.width() && columnWidth - offsetInColumn > visibleSize.width()) { + // the column doesn't fit on a page. Lets split it. + offsetInColumn += visibleSize.width(); + break; + } else if (offsetInColumn > 0) { // we still have a part of a split column to print! + width -= columnWidth - offsetInColumn; + offsetInColumn = 0; + ++column; + continue; + } + + if (width - columnWidth + offsetInColumn < 0) { + break; + } + if (column >= d->model->columnCount()) + break; + ++column; + width -= columnWidth; + } +#ifdef DEBUG_TABLES + painter.setPen(QPen(QColor(Qt::green))); + painter.drawRect(QRectF(0, 0, visibleSize.width() - width, visibleSize.height() - height)); +#endif + view.doLayout(); + // find and paint children which are the cells + QList<QGraphicsItem*> items = scene.items(view.rect()); + QList<QGraphicsItem*>::Iterator iter = items.begin(); + for (;iter != items.end(); ++iter) { + QGraphicsItem *parent = *iter; + while (parent != &view && parent != 0) + parent = parent->parentItem(); + if (parent == 0) + continue; + if (!(*iter)->isVisible()) + continue; + painter.save(); + painter.translate((*iter)->mapToItem(&view, QPointF())); +#ifdef DEBUG_TABLES + QGraphicsWidget *w = dynamic_cast<QGraphicsWidget*>(*iter); + if (w) { + painter.save(); + painter.setPen(QPen(QColor(Qt::red))); + painter.drawRect(QRectF(QPointF(), w->size())); + painter.restore(); + } +#endif + (*iter)->paint(&painter, 0); + painter.restore(); + } + } + } + return true; +} + +#endif diff --git a/src/qprintertableview.h b/src/qprintertableview.h new file mode 100644 index 0000000..be08ca6 --- /dev/null +++ b/src/qprintertableview.h @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Itemviews NG project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 or 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ +#ifndef QTPRINTERTABLEVIEW_H +#define QTPRINTERLTABLEIEW_H + +#include <QtGui/qprinter.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +//QT_MODULE(Gui) + +class QtPrinterTableViewPrivate; +class QtTableModelInterface; +class QtGraphicsHeader; +class QTextDocument; + +class Q_ITEMVIEWSNG_EXPORT QtPrinterTableView +{ +public: + explicit QtPrinterTableView(QPrinter *printer, QtTableModelInterface *model, QtGraphicsHeader *verticalHeader = 0, QtGraphicsHeader *horizontalHeader = 0); + explicit QtPrinterTableView(QtTableModelInterface *model, QtGraphicsHeader *verticalHeader = 0, QtGraphicsHeader *horizontalHeader = 0); + ~QtPrinterTableView(); + + QPrinter *printer(); + bool print(); + + void setOrientation(Qt::Orientation orientation); + Qt::Orientation orientation() const; + + QTextDocument *headerDocument(); + QTextDocument *footerDocument(); + + void setHeaderText(const QString &header); + void setFooterText(const QString &footer); + QString headerText() const; + QString footerText() const; + + // TODO add the setter of the creator object, add static print object + +protected: + QtPrinterTableViewPrivate *d_ptr; + +private: + Q_DECLARE_PRIVATE(QtPrinterTableView) + Q_DISABLE_COPY(QtPrinterTableView) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif //QTPRINTERTABLEVIEW_H diff --git a/src/qprintertableview_p.h b/src/qprintertableview_p.h new file mode 100644 index 0000000..f2927c2 --- /dev/null +++ b/src/qprintertableview_p.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Copyright (C) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the Itemviews NG project on Trolltech Labs. +** +** This file may be used under the terms of the GNU General Public +** License version 2.0 or 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of +** this file. Please review the following information to ensure GNU +** General Public Licensing requirements will be met: +** http://www.fsf.org/licensing/licenses/info/GPLv2.html and +** http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QTPRINTERTABLEVIEW_P_H +#define QTPRINTERTABLEVIEW_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +#ifndef QT_NO_PRINTER +class QTextDocument; + +class QtPrinterTableViewPrivate +{ + Q_DECLARE_PUBLIC(QtPrinterTableView) +public: + QtPrinterTableViewPrivate(QPrinter *printer); + ~QtPrinterTableViewPrivate(); + + QtPrinterTableView *q_ptr; + + bool ownsPrinter; + QPrinter * const printer; + QtTableModelInterface *model; + QtGraphicsHeader *horizontalHeader; + QtGraphicsHeader *verticalHeader; + + Qt::Orientation orientation; + mutable QTextDocument *header; + mutable QTextDocument *footer; + + qreal headerFooterSpacing; // in mm + + /// print a header and return the height we used + qreal printHeader(QPainter &painter); + qreal printFooter(QPainter &painter); + QTextDocument *getOrCreateHeader() const; + QTextDocument *getOrCreateFooter() const; + inline qreal headerFooterSpacingInPixels() { + return headerFooterSpacing * (printer->resolution() / 25.4); + } +}; + +#endif +QT_END_NAMESPACE + +#endif//QTPRINTERTABLEVIEW_P_H diff --git a/src/qtablecontroller.cpp b/src/qtablecontroller.cpp index 1f11ae3..33ce9ae 100644 --- a/src/qtablecontroller.cpp +++ b/src/qtablecontroller.cpp @@ -390,6 +390,9 @@ bool QtTableControllerPrivate::resizeEvent(QResizeEvent *event, const QTransform { Q_UNUSED(event); Q_UNUSED(transform); + if (!view) + return false; + view->updateLayout(); return false; } @@ -845,8 +848,6 @@ QWidget *QtTableController::createEditor(int row, int column, QWidget *contextWi qreal QtTableController::verticalScrollValue() const { Q_D(const QtTableController); - if (d->verticalHeader) - return d->scrollPerRow ? d->verticalHeader->firstSection() : d->verticalHeader->offset(); if (d->view) return d->scrollPerRow ? d->view->firstRow() : d->view->verticalOffset(); return 0; @@ -855,12 +856,7 @@ qreal QtTableController::verticalScrollValue() const void QtTableController::setVerticalScrollValue(qreal value) { Q_D(QtTableController); - if (d->verticalHeader) { - if (d->scrollPerRow) - d->verticalHeader->setFirstSection(value); - else - d->verticalHeader->setOffset(value); - } else if (d->view) { + if (d->view) { if (d->scrollPerRow) d->view->setFirstRow(value); else @@ -871,8 +867,6 @@ void QtTableController::setVerticalScrollValue(qreal value) qreal QtTableController::horizontalScrollValue() const { Q_D(const QtTableController); - if (d->horizontalHeader) - return d->scrollPerColumn ? d->horizontalHeader->firstSection() : d->horizontalHeader->offset(); if (d->view) return d->scrollPerColumn ? d->view->firstColumn() : d->view->horizontalOffset(); return 0; @@ -881,12 +875,7 @@ qreal QtTableController::horizontalScrollValue() const void QtTableController::setHorizontalScrollValue(qreal value) { Q_D(QtTableController); - if (d->horizontalHeader) { - if (d->scrollPerColumn) - d->horizontalHeader->setFirstSection(value); - else - d->horizontalHeader->setOffset(value); - } else if (d->view) { + if (d->view) { if (d->scrollPerColumn) d->view->setFirstColumn(value); else @@ -897,19 +886,7 @@ void QtTableController::setHorizontalScrollValue(qreal value) qreal QtTableController::verticalPageStepValue(qreal *maximumVerticalScrollValue) const { Q_D(const QtTableController); - if (d->verticalHeader) { - if (d->scrollPerRow) { - const int count = d->verticalHeader->sectionCount(); - const int maximum = d->verticalHeader->maximumFirstSection(); - if (maximumVerticalScrollValue) - *maximumVerticalScrollValue = maximum; - return count - maximum; - } else { - if (maximumVerticalScrollValue) - *maximumVerticalScrollValue = d->verticalHeader->maximumOffset(); - return d->verticalHeader->size().height(); - } - } else if (d->view) { + if (d->view) { if (d->scrollPerRow) { const int count = d->view->rowCount(); const int maximum = d->view->maximumFirstRow(); @@ -928,19 +905,7 @@ qreal QtTableController::verticalPageStepValue(qreal *maximumVerticalScrollValue qreal QtTableController::horizontalPageStepValue(qreal *maximumHorizontalScrollValue) const { Q_D(const QtTableController); - if (d->horizontalHeader) { - if (d->scrollPerRow) { - const int count = d->horizontalHeader->sectionCount(); - const int maximum = d->horizontalHeader->maximumFirstSection(); - if (maximumHorizontalScrollValue) - *maximumHorizontalScrollValue = maximum; - return count - maximum; - } else { - if (maximumHorizontalScrollValue) - *maximumHorizontalScrollValue = d->horizontalHeader->maximumOffset(); - return d->horizontalHeader->size().height(); - } - } else if (d->view) { + if (d->view) { if (d->scrollPerRow) { const int count = d->view->columnCount(); const int maximum = d->view->maximumFirstColumn(); @@ -957,12 +922,7 @@ qreal QtTableController::horizontalPageStepValue(qreal *maximumHorizontalScrollV qreal QtTableController::maximumVerticalScrollValue() const { Q_D(const QtTableController); - if (d->verticalHeader) { - if (d->scrollPerRow) - return d->verticalHeader->maximumFirstSection(); - else - return d->verticalHeader->maximumOffset(); - } else if (d->view) { + if (d->view) { if (d->scrollPerRow) return d->view->maximumFirstRow(); else @@ -974,12 +934,7 @@ qreal QtTableController::maximumVerticalScrollValue() const qreal QtTableController::maximumHorizontalScrollValue() const { Q_D(const QtTableController); - if (d->horizontalHeader) { - if (d->scrollPerRow) - return d->horizontalHeader->maximumFirstSection(); - else - return d->horizontalHeader->maximumOffset(); - } else if (d->view) { + if (d->view) { if (d->scrollPerRow) return d->view->maximumFirstColumn(); else diff --git a/src/src.pro b/src/src.pro index e900860..3a2cc0e 100644 --- a/src/src.pro +++ b/src/src.pro @@ -21,6 +21,8 @@ HEADERS += qgraphicsscrollbar.h \ qlistwidgetng_p.h \ qprinterlistview.h \ qprinterlistview_p.h \ + qprintertableview.h \ + qprintertableview_p.h \ qsectionspans_p.h \ qtablecontroller.h \ qtablecontroller_p.h \ @@ -63,6 +65,7 @@ SOURCES += qgraphicsscrollbar.cpp \ qlistselectionmanager.cpp \ qlistwidgetng.cpp \ qprinterlistview.cpp \ + qprintertableview.cpp \ qtablecontroller.cpp \ qgraphicstableview.cpp \ qtabledefaultmodel.cpp \ |