|
1 #include "webview.h" |
|
2 #include "webview_p.h" |
|
3 #include <QtGui> |
|
4 |
|
5 static const int MotionEndWaitTime = 2000; |
|
6 static const int TileSideLength = 128; |
|
7 |
|
8 WebViewPrivate::WebViewPrivate(WebView *w) |
|
9 : q(w) |
|
10 , cache(0) |
|
11 { |
|
12 web = new QGraphicsWebView; |
|
13 |
|
14 web->setParentItem(q->viewport()); |
|
15 |
|
16 web->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
17 web->page()->mainFrame()->setScrollBarPolicy( |
|
18 Qt::Horizontal, Qt::ScrollBarAlwaysOff); |
|
19 web->page()->mainFrame()->setScrollBarPolicy( |
|
20 Qt::Vertical, Qt::ScrollBarAlwaysOff); |
|
21 web->setZValue(3); |
|
22 |
|
23 // cache = new WebViewCache(web); |
|
24 // web->setGraphicsEffect(cache); |
|
25 |
|
26 adjustSize(); |
|
27 } |
|
28 |
|
29 void WebViewPrivate::adjustSize() |
|
30 { |
|
31 QSizeF contentSize = web->page()->mainFrame()->contentsSize(); |
|
32 QPointF pos = web->pos(); |
|
33 |
|
34 qreal w = qMax(contentSize.width(), q->viewport()->boundingRect().width()); |
|
35 qreal h = qMax(contentSize.height(), q->viewport()->boundingRect().height()); |
|
36 |
|
37 if (web->boundingRect().size() != QSizeF(w, h)) { |
|
38 //qDebug() << "WebView: adjustSize:" << QSizeF(w, h); |
|
39 |
|
40 web->resize(w, h); |
|
41 web->setPos(pos); |
|
42 |
|
43 if (w > q->viewport()->boundingRect().width()) |
|
44 q->horizontalScrollBar()->setSliderSize(w); |
|
45 else |
|
46 q->horizontalScrollBar()->setSliderSize(0.0); |
|
47 |
|
48 |
|
49 if (h > q->viewport()->boundingRect().height()) |
|
50 q->verticalScrollBar()->setSliderSize(h); |
|
51 else |
|
52 q->verticalScrollBar()->setSliderSize(0.0); |
|
53 } |
|
54 } |
|
55 |
|
56 void WebViewPrivate::_q_loadStarted() |
|
57 { |
|
58 qDebug() << "WebView: load started"; |
|
59 adjustSize(); |
|
60 } |
|
61 |
|
62 void WebViewPrivate::_q_loadProgress(int progress) |
|
63 { |
|
64 Q_UNUSED(progress) |
|
65 // qDebug() << "WebView: load progress" << progress; |
|
66 adjustSize(); |
|
67 } |
|
68 |
|
69 void WebViewPrivate::_q_loadFinished(bool ok) |
|
70 { |
|
71 qDebug() << "WebView: load finished" << (ok ? "ok" : "not ok"); |
|
72 adjustSize(); |
|
73 } |
|
74 |
|
75 void WebViewPrivate::_q_viewportChanged(QGraphicsWidget* viewport) |
|
76 { |
|
77 web->setParentItem(viewport); |
|
78 viewport->setFlag(QGraphicsItem::ItemClipsChildrenToShape, |
|
79 true); |
|
80 adjustSize(); |
|
81 } |
|
82 |
|
83 void WebViewPrivate::_q_motionEnded() |
|
84 { |
|
85 motionTimer.stop(); |
|
86 qDebug() << "Motion ended"; |
|
87 q->prepareGeometryChange(); |
|
88 } |
|
89 |
|
90 WebViewCache::WebViewCache(QGraphicsWebView *webView) |
|
91 : m_webView(webView) |
|
92 { |
|
93 |
|
94 } |
|
95 |
|
96 WebViewCache::~WebViewCache() |
|
97 { |
|
98 } |
|
99 |
|
100 void WebViewCache::draw(QPainter * painter, QGraphicsEffectSource * source) |
|
101 { |
|
102 const QGraphicsItem *item = source->graphicsItem(); |
|
103 |
|
104 QSizeF itemSize = item->boundingRect().size(); |
|
105 |
|
106 if (!qFuzzyCompare(itemSize.width(), m_itemSize.width()) || |
|
107 !qFuzzyCompare(itemSize.height(), m_itemSize.height())) { |
|
108 qDebug() << "Refresh tile cache, for new size" << itemSize; |
|
109 |
|
110 for (int i = 0; i < m_tilePixmaps.size(); i++) { |
|
111 QPixmapCache::remove(m_tilePixmaps[i]); |
|
112 } |
|
113 |
|
114 m_tilePixmaps.clear(); |
|
115 m_tileRects.clear(); |
|
116 |
|
117 int itemWidth = itemSize.width() + 0.5; |
|
118 int itemHeight = itemSize.height() + 0.5; |
|
119 |
|
120 int tilesX = itemWidth / TileSideLength; |
|
121 int tilesY = itemHeight / TileSideLength; |
|
122 |
|
123 if ((itemWidth % TileSideLength) != 0) { |
|
124 ++tilesX; |
|
125 } |
|
126 |
|
127 if ((itemHeight % TileSideLength) != 0) { |
|
128 ++tilesY; |
|
129 } |
|
130 |
|
131 int tilesCount = tilesX * tilesY; |
|
132 |
|
133 m_tilePixmaps.resize(tilesCount); |
|
134 m_tileRects.resize(tilesCount); |
|
135 |
|
136 for (int i = 0; i < tilesX; i++) { |
|
137 for (int j = 0; j < tilesY; j++) { |
|
138 int x = i * TileSideLength; |
|
139 int y = j * TileSideLength; |
|
140 |
|
141 m_tileRects[i + j * tilesX] |
|
142 = QRectF(x, y, TileSideLength, TileSideLength); |
|
143 } |
|
144 } |
|
145 |
|
146 m_itemSize = itemSize; |
|
147 } |
|
148 |
|
149 const QGraphicsItem *parentItem = item->parentItem(); |
|
150 QPointF itemPos = item->pos(); |
|
151 QRectF parentRect = parentItem->boundingRect(); |
|
152 |
|
153 for (int i = 0; i < m_tileRects.size(); i++) { |
|
154 QRectF tileRect = m_tileRects[i].translated(itemPos); |
|
155 |
|
156 if (!tileRect.intersects(parentRect) && !tileRect.contains(parentRect)) { |
|
157 continue; |
|
158 } |
|
159 |
|
160 QPixmap tilePixmap; |
|
161 |
|
162 if (!QPixmapCache::find(m_tilePixmaps[i], &tilePixmap)) { |
|
163 tilePixmap = QPixmap(TileSideLength, TileSideLength); |
|
164 |
|
165 QWebFrame *webFrame = m_webView->page()->mainFrame(); |
|
166 |
|
167 QPainter tilePainter(&tilePixmap); |
|
168 tilePainter.translate(-m_tileRects[i].left(), -m_tileRects[i].top()); |
|
169 webFrame->render(&tilePainter, m_tileRects[i].toRect()); |
|
170 tilePainter.end(); |
|
171 |
|
172 m_tilePixmaps[i] = QPixmapCache::insert(tilePixmap); |
|
173 } |
|
174 |
|
175 tileRect = tileRect.translated(-itemPos); |
|
176 |
|
177 painter->drawPixmap(tileRect.topLeft(), tilePixmap); |
|
178 } |
|
179 } |
|
180 |
|
181 WebView::WebView(QGraphicsWidget *parent) |
|
182 : AbstractScrollArea(parent) |
|
183 , d(new WebViewPrivate(this)) |
|
184 { |
|
185 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
|
186 setContentsMargins(0, 0, 0, 0); |
|
187 connect(d->web->page(), SIGNAL(loadStarted()), |
|
188 this, SLOT(_q_loadStarted())); |
|
189 connect(d->web->page(), SIGNAL(loadProgress(int)), |
|
190 this, SLOT(_q_loadProgress(int))); |
|
191 connect(d->web->page(), SIGNAL(loadFinished(bool)), |
|
192 this, SLOT(_q_loadFinished(bool))); |
|
193 connect(this, SIGNAL(viewportChanged(QGraphicsWidget*)), |
|
194 this, SLOT(_q_viewportChanged(QGraphicsWidget*))); |
|
195 connect(&d->motionTimer, SIGNAL(timeout()), |
|
196 this, SLOT(_q_motionEnded())); |
|
197 } |
|
198 |
|
199 WebView::~WebView() |
|
200 { |
|
201 d->web->setGraphicsEffect(0); |
|
202 delete d->cache; |
|
203 } |
|
204 |
|
205 void WebView::setUrl(const QUrl& url) |
|
206 { |
|
207 d->adjustSize(); |
|
208 d->web->setUrl(url); |
|
209 } |
|
210 |
|
211 void WebView::scrollContentsBy(qreal dx, qreal dy) |
|
212 { |
|
213 if (qFuzzyCompare((float)dy, 0.0f) && qFuzzyCompare((float)dx, 0.0f)) |
|
214 return; |
|
215 |
|
216 if (!d->motionTimer.isActive()) { |
|
217 d->motionTimer.start(MotionEndWaitTime); |
|
218 } |
|
219 |
|
220 QSizeF contentSize = d->web->page()->mainFrame()->contentsSize(); |
|
221 QRectF viewportRect = viewport()->boundingRect(); |
|
222 QPointF pos = d->web->pos(); |
|
223 |
|
224 qreal w = qMax(contentSize.width(), viewportRect.width()); |
|
225 qreal h = qMax(contentSize.height(), viewportRect.height()); |
|
226 |
|
227 qreal minx = qMin(0.0f, (float) -(w - viewportRect.width())); |
|
228 qreal miny = qMin(0.0f, (float) -(h - viewportRect.height())); |
|
229 |
|
230 qreal x = d->web->pos().x() - dx; |
|
231 |
|
232 if (x < minx) |
|
233 x = minx; |
|
234 else if (x > 0) |
|
235 x = 0.0; |
|
236 |
|
237 qreal y = d->web->pos().y() - dy; |
|
238 |
|
239 if (y < miny) |
|
240 y = miny; |
|
241 else if (y > 0) |
|
242 y = 0.0; |
|
243 |
|
244 d->web->setPos(x, y); |
|
245 } |
|
246 |
|
247 QSizeF WebView::sizeHint(Qt::SizeHint which, const QSizeF & constraint) const |
|
248 { |
|
249 if (which == Qt::PreferredSize) { |
|
250 QSizeF contentSize = d->web->page()->mainFrame()->contentsSize(); |
|
251 return contentSize; |
|
252 } |
|
253 |
|
254 return AbstractScrollArea::sizeHint(which, constraint); |
|
255 } |
|
256 |
|
257 void WebView::resizeEvent(QGraphicsSceneResizeEvent *event) |
|
258 { |
|
259 AbstractScrollArea::resizeEvent(event); |
|
260 d->adjustSize(); |
|
261 } |
|
262 |
|
263 #include "moc_webview.cpp" |