source: trunk/src/gui/widgets/qprintpreviewwidget.cpp@ 117

Last change on this file since 117 was 2, checked in by Dmitry A. Kuminov, 17 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 24.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qprintpreviewwidget.h"
43#include <private/qprinter_p.h>
44
45#include <QtCore/qmath.h>
46#include <QtGui/qboxlayout.h>
47#include <QtGui/qgraphicsitem.h>
48#include <QtGui/qgraphicsview.h>
49#include <QtGui/qscrollbar.h>
50#include <QtGui/qstyleoption.h>
51
52#ifndef QT_NO_PRINTPREVIEWWIDGET
53
54QT_BEGIN_NAMESPACE
55
56namespace {
57class PageItem : public QGraphicsItem
58{
59public:
60 PageItem(int _pageNum, const QPicture* _pagePicture, QSize _paperSize, QRect _pageRect)
61 : pageNum(_pageNum), pagePicture(_pagePicture),
62 paperSize(_paperSize), pageRect(_pageRect)
63 {
64 qreal border = qMax(paperSize.height(), paperSize.width()) / 25;
65 brect = QRectF(QPointF(-border, -border),
66 QSizeF(paperSize)+QSizeF(2*border, 2*border));
67 setCacheMode(DeviceCoordinateCache);
68 }
69
70 inline QRectF boundingRect() const
71 { return brect; }
72
73 inline int pageNumber() const
74 { return pageNum; }
75
76 void paint(QPainter *painter, const QStyleOptionGraphicsItem *item, QWidget *widget);
77
78private:
79 int pageNum;
80 const QPicture* pagePicture;
81 QSize paperSize;
82 QRect pageRect;
83 QRectF brect;
84};
85
86void PageItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
87{
88 Q_UNUSED(widget);
89
90#if 0
91 // Draw item bounding rect, for debugging
92 painter->save();
93 painter->setPen(QPen(Qt::red, 0));
94 painter->setBrush(Qt::NoBrush);
95 painter->drawRect(QRectF(-border()+1.0, -border()+1.0, boundingRect().width()-2, boundingRect().height()-2));
96 painter->restore();
97#endif
98
99 QRectF paperRect(0,0, paperSize.width(), paperSize.height());
100
101 painter->setClipRect(paperRect & option->exposedRect);
102 painter->fillRect(paperRect, Qt::white);
103 if (!pagePicture)
104 return;
105 painter->drawPicture(pageRect.topLeft(), *pagePicture);
106
107 // Effect: make anything drawn in the margins look washed out.
108 QPainterPath path;
109 path.addRect(paperRect);
110 path.addRect(pageRect);
111 painter->setPen(QPen(Qt::NoPen));
112 painter->setBrush(QColor(255, 255, 255, 180));
113 painter->drawPath(path);
114
115 painter->setClipRect(option->exposedRect);
116#if 0
117 // Draw frame around paper.
118 painter->setPen(QPen(Qt::black, 0));
119 painter->setBrush(Qt::NoBrush);
120 painter->drawRect(paperRect);
121#endif
122
123 // Draw shadow
124 qreal shWidth = paperRect.width()/100;
125 QRectF rshadow(paperRect.topRight() + QPointF(0, shWidth),
126 paperRect.bottomRight() + QPointF(shWidth, 0));
127 QLinearGradient rgrad(rshadow.topLeft(), rshadow.topRight());
128 rgrad.setColorAt(0.0, QColor(0,0,0,255));
129 rgrad.setColorAt(1.0, QColor(0,0,0,0));
130 painter->fillRect(rshadow, QBrush(rgrad));
131 QRectF bshadow(paperRect.bottomLeft() + QPointF(shWidth, 0),
132 paperRect.bottomRight() + QPointF(0, shWidth));
133 QLinearGradient bgrad(bshadow.topLeft(), bshadow.bottomLeft());
134 bgrad.setColorAt(0.0, QColor(0,0,0,255));
135 bgrad.setColorAt(1.0, QColor(0,0,0,0));
136 painter->fillRect(bshadow, QBrush(bgrad));
137 QRectF cshadow(paperRect.bottomRight(),
138 paperRect.bottomRight() + QPointF(shWidth, shWidth));
139 QRadialGradient cgrad(cshadow.topLeft(), shWidth, cshadow.topLeft());
140 cgrad.setColorAt(0.0, QColor(0,0,0,255));
141 cgrad.setColorAt(1.0, QColor(0,0,0,0));
142 painter->fillRect(cshadow, QBrush(cgrad));
143
144 // todo: drawtext "Page N" below paper
145}
146
147class GraphicsView : public QGraphicsView
148{
149 Q_OBJECT
150public:
151 GraphicsView(QWidget* parent = 0)
152 : QGraphicsView(parent)
153 {}
154signals:
155 void resized();
156
157protected:
158 void resizeEvent(QResizeEvent* e)
159 {
160 QGraphicsView::resizeEvent(e);
161 emit resized();
162 }
163
164 void showEvent(QShowEvent* e)
165 {
166 QGraphicsView::showEvent(e);
167 emit resized();
168 }
169};
170
171} // anonymous namespace
172
173class QPrintPreviewWidgetPrivate
174{
175 Q_DECLARE_PUBLIC(QPrintPreviewWidget)
176public:
177 QPrintPreviewWidgetPrivate(QPrintPreviewWidget *q)
178 : q_ptr(q), scene(0), curPage(1),
179 viewMode(QPrintPreviewWidget::SinglePageView),
180 zoomMode(QPrintPreviewWidget::FitInView),
181 zoomFactor(1), initialized(false), fitting(true)
182 {}
183
184 // private slots
185 void _q_fit(bool doFitting = false);
186 void _q_updateCurrentPage();
187
188 void init();
189 void populateScene();
190 void layoutPages();
191 void generatePreview();
192 void setCurrentPage(int pageNumber);
193 void zoom(qreal zoom);
194 void setZoomFactor(qreal zoomFactor);
195 int calcCurrentPage();
196
197 QPrintPreviewWidget *q_ptr;
198 GraphicsView *graphicsView;
199 QGraphicsScene *scene;
200
201 int curPage;
202 QList<const QPicture *> pictures;
203 QList<QGraphicsItem *> pages;
204
205 QPrintPreviewWidget::ViewMode viewMode;
206 QPrintPreviewWidget::ZoomMode zoomMode;
207 qreal zoomFactor;
208 bool ownPrinter;
209 QPrinter* printer;
210 bool initialized;
211 bool fitting;
212};
213
214void QPrintPreviewWidgetPrivate::_q_fit(bool doFitting)
215{
216 Q_Q(QPrintPreviewWidget);
217
218 if (curPage < 1 || curPage > pages.count())
219 return;
220
221 if (!doFitting && !fitting)
222 return;
223
224 if (doFitting && fitting) {
225 QRect viewRect = graphicsView->viewport()->rect();
226 if (zoomMode == QPrintPreviewWidget::FitInView) {
227 QList<QGraphicsItem*> containedItems = graphicsView->items(viewRect, Qt::ContainsItemBoundingRect);
228 foreach(QGraphicsItem* item, containedItems) {
229 PageItem* pg = static_cast<PageItem*>(item);
230 if (pg->pageNumber() == curPage)
231 return;
232 }
233 }
234
235 int newPage = calcCurrentPage();
236 if (newPage != curPage)
237 curPage = newPage;
238 }
239
240 QRectF target = pages.at(curPage-1)->sceneBoundingRect();
241 if (viewMode == QPrintPreviewWidget::FacingPagesView) {
242 // fit two pages
243 if (curPage % 2)
244 target.setLeft(target.left() - target.width());
245 else
246 target.setRight(target.right() + target.width());
247 } else if (viewMode == QPrintPreviewWidget::AllPagesView) {
248 target = scene->itemsBoundingRect();
249 }
250
251 if (zoomMode == QPrintPreviewWidget::FitToWidth) {
252 QTransform t;
253 qreal scale = graphicsView->viewport()->width() / target.width();
254 t.scale(scale, scale);
255 graphicsView->setTransform(t);
256 if (doFitting && fitting) {
257 QRectF viewSceneRect = graphicsView->viewportTransform().mapRect(graphicsView->viewport()->rect());
258 viewSceneRect.moveTop(target.top());
259 graphicsView->ensureVisible(viewSceneRect); // Nah...
260 }
261 } else {
262 graphicsView->fitInView(target, Qt::KeepAspectRatio);
263 if (zoomMode == QPrintPreviewWidget::FitInView) {
264 int step = qRound(graphicsView->matrix().mapRect(target).height());
265 graphicsView->verticalScrollBar()->setSingleStep(step);
266 graphicsView->verticalScrollBar()->setPageStep(step);
267 }
268 }
269
270 zoomFactor = graphicsView->transform().m11() * (float(printer->logicalDpiY()) / q->logicalDpiY());
271 emit q->previewChanged();
272}
273
274void QPrintPreviewWidgetPrivate::_q_updateCurrentPage()
275{
276 Q_Q(QPrintPreviewWidget);
277
278 if (viewMode == QPrintPreviewWidget::AllPagesView)
279 return;
280
281 int newPage = calcCurrentPage();
282 if (newPage != curPage) {
283 curPage = newPage;
284 emit q->previewChanged();
285 }
286}
287
288int QPrintPreviewWidgetPrivate::calcCurrentPage()
289{
290 int maxArea = 0;
291 int newPage = curPage;
292 QRect viewRect = graphicsView->viewport()->rect();
293 QList<QGraphicsItem*> items = graphicsView->items(viewRect);
294 for (int i=0; i<items.size(); ++i) {
295 PageItem* pg = static_cast<PageItem*>(items.at(i));
296 QRect overlap = graphicsView->mapFromScene(pg->sceneBoundingRect()).boundingRect() & viewRect;
297 int area = overlap.width() * overlap.height();
298 if (area > maxArea) {
299 maxArea = area;
300 newPage = pg->pageNumber();
301 } else if (area == maxArea && pg->pageNumber() < newPage) {
302 newPage = pg->pageNumber();
303 }
304 }
305 return newPage;
306}
307
308void QPrintPreviewWidgetPrivate::init()
309{
310 Q_Q(QPrintPreviewWidget);
311
312 graphicsView = new GraphicsView;
313 graphicsView->setInteractive(false);
314 graphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
315 graphicsView->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
316 QObject::connect(graphicsView->verticalScrollBar(), SIGNAL(valueChanged(int)),
317 q, SLOT(_q_updateCurrentPage()));
318 QObject::connect(graphicsView, SIGNAL(resized()), q, SLOT(_q_fit()));
319
320 scene = new QGraphicsScene(graphicsView);
321 scene->setBackgroundBrush(Qt::gray);
322 graphicsView->setScene(scene);
323
324 QVBoxLayout *layout = new QVBoxLayout;
325 q->setLayout(layout);
326 layout->setContentsMargins(0, 0, 0, 0);
327 layout->addWidget(graphicsView);
328}
329
330void QPrintPreviewWidgetPrivate::populateScene()
331{
332 // remove old pages
333 for (int i = 0; i < pages.size(); i++)
334 scene->removeItem(pages.at(i));
335 qDeleteAll(pages);
336 pages.clear();
337
338 int numPages = pictures.count();
339 QSize paperSize = printer->paperRect().size();
340 QRect pageRect = printer->pageRect();
341
342 for (int i = 0; i < numPages; i++) {
343 PageItem* item = new PageItem(i+1, pictures.at(i), paperSize, pageRect);
344 scene->addItem(item);
345 pages.append(item);
346 }
347}
348
349void QPrintPreviewWidgetPrivate::layoutPages()
350{
351 int numPages = pages.count();
352 if (numPages < 1)
353 return;
354
355 int numPagePlaces = numPages;
356 int cols = 1; // singleMode and default
357 if (viewMode == QPrintPreviewWidget::AllPagesView) {
358 if (printer->orientation() == QPrinter::Portrait)
359 cols = qCeil(qSqrt((float) numPages));
360 else
361 cols = qFloor(qSqrt((float) numPages));
362 cols += cols % 2; // Nicer with an even number of cols
363 }
364 else if (viewMode == QPrintPreviewWidget::FacingPagesView) {