1 | /* |
---|
2 | |
---|
3 | Copyright 2012-2015 Adam Reichold |
---|
4 | |
---|
5 | This file is part of qpdfview. |
---|
6 | |
---|
7 | qpdfview is free software: you can redistribute it and/or modify |
---|
8 | it under the terms of the GNU General Public License as published by |
---|
9 | the Free Software Foundation, either version 2 of the License, or |
---|
10 | (at your option) any later version. |
---|
11 | |
---|
12 | qpdfview is distributed in the hope that it will be useful, |
---|
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
15 | GNU General Public License for more details. |
---|
16 | |
---|
17 | You should have received a copy of the GNU General Public License |
---|
18 | along with qpdfview. If not, see <http://www.gnu.org/licenses/>. |
---|
19 | |
---|
20 | */ |
---|
21 | |
---|
22 | #include "pageitem.h" |
---|
23 | |
---|
24 | #include <QApplication> |
---|
25 | #include <QClipboard> |
---|
26 | #include <QFileDialog> |
---|
27 | #include <QGraphicsProxyWidget> |
---|
28 | #include <QGraphicsScene> |
---|
29 | #include <QGraphicsSceneHoverEvent> |
---|
30 | #include <qmath.h> |
---|
31 | #include <QMenu> |
---|
32 | #include <QMessageBox> |
---|
33 | #include <QPainter> |
---|
34 | #include <QStyleOptionGraphicsItem> |
---|
35 | #include <QTimer> |
---|
36 | #include <QToolTip> |
---|
37 | #include <QUrl> |
---|
38 | |
---|
39 | #include "settings.h" |
---|
40 | #include "model.h" |
---|
41 | #include "rendertask.h" |
---|
42 | #include "tileitem.h" |
---|
43 | |
---|
44 | namespace |
---|
45 | { |
---|
46 | |
---|
47 | using namespace qpdfview; |
---|
48 | |
---|
49 | const int largeTilesThreshold = 8; |
---|
50 | const int veryLargeTilesThreshold = 16; |
---|
51 | |
---|
52 | const qreal proxyPadding = 2.0; |
---|
53 | |
---|
54 | bool modifiersUseMouseButton(Settings* settings, Qt::MouseButton mouseButton) |
---|
55 | { |
---|
56 | return ((settings->pageItem().copyToClipboardModifiers() | settings->pageItem().addAnnotationModifiers()) & mouseButton) != 0; |
---|
57 | } |
---|
58 | |
---|
59 | } // anonymous |
---|
60 | |
---|
61 | namespace qpdfview |
---|
62 | { |
---|
63 | |
---|
64 | Settings* PageItem::s_settings = 0; |
---|
65 | |
---|
66 | PageItem::PageItem(Model::Page* page, int index, PaintMode paintMode, QGraphicsItem* parent) : QGraphicsObject(parent), |
---|
67 | m_page(page), |
---|
68 | m_size(page->size()), |
---|
69 | m_cropRect(), |
---|
70 | m_index(index), |
---|
71 | m_paintMode(paintMode), |
---|
72 | m_highlights(), |
---|
73 | m_links(), |
---|
74 | m_annotations(), |
---|
75 | m_formFields(), |
---|
76 | m_rubberBandMode(ModifiersMode), |
---|
77 | m_rubberBand(), |
---|
78 | m_annotationOverlay(), |
---|
79 | m_formFieldOverlay(), |
---|
80 | m_renderParam(), |
---|
81 | m_transform(), |
---|
82 | m_normalizedTransform(), |
---|
83 | m_boundingRect(), |
---|
84 | m_tileItems() |
---|
85 | { |
---|
86 | if(s_settings == 0) |
---|
87 | { |
---|
88 | s_settings = Settings::instance(); |
---|
89 | } |
---|
90 | |
---|
91 | setAcceptHoverEvents(true); |
---|
92 | |
---|
93 | setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, useTiling()); |
---|
94 | |
---|
95 | if(!useTiling()) |
---|
96 | { |
---|
97 | m_tileItems.resize(1); |
---|
98 | m_tileItems.squeeze(); |
---|
99 | |
---|
100 | m_tileItems.replace(0, new TileItem(this)); |
---|
101 | } |
---|
102 | |
---|
103 | QTimer::singleShot(0, this, SLOT(loadInteractiveElements())); |
---|
104 | |
---|
105 | prepareGeometry(); |
---|
106 | } |
---|
107 | |
---|
108 | PageItem::~PageItem() |
---|
109 | { |
---|
110 | hideAnnotationOverlay(false); |
---|
111 | hideFormFieldOverlay(false); |
---|
112 | |
---|
113 | TileItem::dropCachedPixmaps(this); |
---|
114 | |
---|
115 | qDeleteAll(m_links); |
---|
116 | qDeleteAll(m_annotations); |
---|
117 | qDeleteAll(m_formFields); |
---|
118 | } |
---|
119 | |
---|
120 | QRectF PageItem::boundingRect() const |
---|
121 | { |
---|
122 | if(m_cropRect.isNull()) |
---|
123 | { |
---|
124 | return m_boundingRect; |
---|
125 | } |
---|
126 | |
---|
127 | QRectF boundingRect; |
---|
128 | |
---|
129 | boundingRect.setLeft(m_boundingRect.left() + m_cropRect.left() * m_boundingRect.width()); |
---|
130 | boundingRect.setTop(m_boundingRect.top() + m_cropRect.top() * m_boundingRect.height()); |
---|
131 | boundingRect.setWidth(m_cropRect.width() * m_boundingRect.width()); |
---|
132 | boundingRect.setHeight(m_cropRect.height() * m_boundingRect.height()); |
---|
133 | |
---|
134 | return boundingRect; |
---|
135 | } |
---|
136 | |
---|
137 | void PageItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget*) |
---|
138 | { |
---|
139 | paintPage(painter, option->exposedRect); |
---|
140 | |
---|
141 | paintLinks(painter); |
---|
142 | paintFormFields(painter); |
---|
143 | |
---|
144 | paintHighlights(painter); |
---|
145 | paintRubberBand(painter); |
---|
146 | } |
---|
147 | |
---|
148 | QSizeF PageItem::displayedSize(const RenderParam& renderParam) const |
---|
149 | { |
---|
150 | const bool rotationChanged = m_renderParam.rotation() != renderParam.rotation(); |
---|
151 | |
---|
152 | const bool flagsChanged = m_renderParam.flags() != renderParam.flags(); |
---|
153 | |
---|
154 | const bool useCropRect = !m_cropRect.isNull() && !rotationChanged && !flagsChanged; |
---|
155 | |
---|
156 | const qreal cropWidth = useCropRect ? m_cropRect.width() : 1.0; |
---|
157 | const qreal cropHeight = useCropRect ? m_cropRect.height() : 1.0; |
---|
158 | |
---|
159 | switch(renderParam.rotation()) |
---|
160 | { |
---|
161 | default: |
---|
162 | case RotateBy0: |
---|
163 | case RotateBy180: |
---|
164 | return QSizeF(renderParam.resolutionX() / 72.0 * cropWidth * m_size.width(), |
---|
165 | renderParam.resolutionY() / 72.0 * cropHeight * m_size.height()); |
---|
166 | case RotateBy90: |
---|
167 | case RotateBy270: |
---|
168 | return QSizeF(renderParam.resolutionX() / 72.0 * cropHeight * m_size.height(), |
---|
169 | renderParam.resolutionY() / 72.0 * cropWidth * m_size.width()); |
---|
170 | } |
---|
171 | } |
---|
172 | |
---|
173 | void PageItem::setHighlights(const QList< QRectF >& highlights) |
---|
174 | { |
---|
175 | m_highlights = highlights; |
---|
176 | |
---|
177 | update(); |
---|
178 | } |
---|
179 | |
---|
180 | void PageItem::setRubberBandMode(RubberBandMode rubberBandMode) |
---|
181 | { |
---|
182 | if(m_rubberBandMode != rubberBandMode && rubberBandMode >= 0 && rubberBandMode < NumberOfRubberBandModes) |
---|
183 | { |
---|
184 | m_rubberBandMode = rubberBandMode; |
---|
185 | |
---|
186 | if(m_rubberBandMode == ModifiersMode) |
---|
187 | { |
---|
188 | unsetCursor(); |
---|
189 | } |
---|
190 | else |
---|
191 | { |
---|
192 | setCursor(Qt::CrossCursor); |
---|
193 | } |
---|
194 | } |
---|
195 | } |
---|
196 | |
---|
197 | void PageItem::setRenderParam(const RenderParam& renderParam) |
---|
198 | { |
---|
199 | if(m_renderParam != renderParam) |
---|
200 | { |
---|
201 | const bool resolutionChanged = m_renderParam.resolutionX() != renderParam.resolutionX() |
---|
202 | || m_renderParam.resolutionY() != renderParam.resolutionY() |
---|
203 | || !qFuzzyCompare(m_renderParam.devicePixelRatio(), renderParam.devicePixelRatio()) |
---|
204 | || !qFuzzyCompare(m_renderParam.scaleFactor(), renderParam.scaleFactor()); |
---|
205 | |
---|
206 | const bool rotationChanged = m_renderParam.rotation() != renderParam.rotation(); |
---|
207 | |
---|
208 | const RenderFlags changedFlags = m_renderParam.flags() ^ renderParam.flags(); |
---|
209 | |
---|
210 | refresh(!rotationChanged && changedFlags == 0); |
---|
211 | |
---|
212 | m_renderParam = renderParam; |
---|
213 | |
---|
214 | if(resolutionChanged || rotationChanged) |
---|
215 | { |
---|
216 | prepareGeometryChange(); |
---|
217 | prepareGeometry(); |
---|
218 | } |
---|
219 | |
---|
220 | if(changedFlags.testFlag(TrimMargins)) |
---|
221 | { |
---|
222 | setFlag(QGraphicsItem::ItemClipsToShape, m_renderParam.trimMargins()); |
---|
223 | } |
---|
224 | } |
---|
225 | } |
---|
226 | |
---|
227 | void PageItem::refresh(bool keepObsoletePixmaps, bool dropCachedPixmaps) |
---|
228 | { |
---|
229 | if(!useTiling()) |
---|
230 | { |
---|
231 | m_tileItems.first()->refresh(keepObsoletePixmaps); |
---|
232 | } |
---|
233 | else |
---|
234 | { |
---|
235 | foreach(TileItem* tile, m_tileItems) |
---|
236 | { |
---|
237 | tile->refresh(keepObsoletePixmaps); |
---|
238 | } |
---|
239 | } |
---|
240 | |
---|
241 | if(!keepObsoletePixmaps) |
---|
242 | { |
---|
243 | prepareGeometryChange(); |
---|
244 | |
---|
245 | m_cropRect = QRectF(); |
---|
246 | } |
---|
247 | |
---|
248 | if(dropCachedPixmaps) |
---|
249 | { |
---|
250 | TileItem::dropCachedPixmaps(this); |
---|
251 | } |
---|
252 | |
---|
253 | update(); |
---|
254 | } |
---|
255 | |
---|
256 | int PageItem::startRender(bool prefetch) |
---|
257 | { |
---|
258 | int cost = 0; |
---|
259 | |
---|
260 | if(!useTiling()) |
---|
261 | { |
---|
262 | cost += m_tileItems.first()->startRender(prefetch); |
---|
263 | } |
---|
264 | else |
---|
265 | { |
---|
266 | foreach(TileItem* tile, m_tileItems) |
---|
267 | { |
---|
268 | cost += tile->startRender(prefetch); |
---|
269 | } |
---|
270 | } |
---|
271 | |
---|
272 | return cost; |
---|
273 | } |
---|
274 | |
---|
275 | void PageItem::cancelRender() |
---|
276 | { |
---|
277 | if(!useTiling()) |
---|
278 | { |
---|
279 | m_tileItems.first()->cancelRender(); |
---|
280 | } |
---|
281 | else |
---|
282 | { |
---|
283 | foreach(TileItem* tile, m_exposedTileItems) |
---|
284 | { |
---|
285 | tile->cancelRender(); |
---|
286 | } |
---|
287 | |
---|
288 | m_exposedTileItems.clear(); |
---|
289 | } |
---|
290 | } |
---|
291 | |
---|
292 | void PageItem::showAnnotationOverlay(Model::Annotation* selectedAnnotation) |
---|
293 | { |
---|
294 | if(s_settings->pageItem().annotationOverlay()) |
---|
295 | { |
---|
296 | showOverlay(m_annotationOverlay, SLOT(hideAnnotationOverlay()), m_annotations, selectedAnnotation); |
---|
297 | } |
---|
298 | else |
---|
299 | { |
---|
300 | hideAnnotationOverlay(false); |
---|
301 | |
---|
302 | addProxy(m_annotationOverlay, SLOT(hideAnnotationOverlay()), selectedAnnotation); |
---|
303 | m_annotationOverlay.value(selectedAnnotation)->widget()->setFocus(); |
---|
304 | } |
---|
305 | } |
---|
306 | |
---|
307 | void PageItem::hideAnnotationOverlay(bool deleteLater) |
---|
308 | { |
---|
309 | hideOverlay(m_annotationOverlay, deleteLater); |
---|
310 | } |
---|
311 | |
---|
312 | void PageItem::updateAnnotationOverlay() |
---|
313 | { |
---|
314 | updateOverlay(m_annotationOverlay); |
---|
315 | } |
---|
316 | |
---|
317 | void PageItem::showFormFieldOverlay(Model::FormField* selectedFormField) |
---|
318 | { |
---|
319 | if(s_settings->pageItem().formFieldOverlay()) |
---|
320 | { |
---|
321 | showOverlay(m_formFieldOverlay, SLOT(hideFormFieldOverlay()), m_formFields, selectedFormField); |
---|
322 | } |
---|
323 | else |
---|
324 | { |
---|
325 | hideFormFieldOverlay(false); |
---|
326 | |
---|
327 | addProxy(m_formFieldOverlay, SLOT(hideFormFieldOverlay()), selectedFormField); |
---|
328 | m_formFieldOverlay.value(selectedFormField)->widget()->setFocus(); |
---|
329 | } |
---|
330 | } |
---|
331 | |
---|
332 | void PageItem::updateFormFieldOverlay() |
---|
333 | { |
---|
334 | updateOverlay(m_formFieldOverlay); |
---|
335 | } |
---|
336 | |
---|
337 | void PageItem::hideFormFieldOverlay(bool deleteLater) |
---|
338 | { |
---|
339 | hideOverlay(m_formFieldOverlay, deleteLater); |
---|
340 | } |
---|
341 | |
---|
342 | void PageItem::hoverEnterEvent(QGraphicsSceneHoverEvent*) |
---|
343 | { |
---|
344 | } |
---|
345 | |
---|
346 | void PageItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event) |
---|
347 | { |
---|
348 | if(m_rubberBandMode == ModifiersMode && event->modifiers() == Qt::NoModifier) |
---|
349 | { |
---|
350 | // links |
---|
351 | |
---|
352 | foreach(const Model::Link* link, m_links) |
---|
353 | { |
---|
354 | if(m_normalizedTransform.map(link->boundary).contains(event->pos())) |
---|
355 | { |
---|
356 | if(link->page != -1 && (link->urlOrFileName.isNull() || !presentationMode())) |
---|
357 | { |
---|
358 | setCursor(Qt::PointingHandCursor); |
---|
359 | |
---|
360 | if(link->urlOrFileName.isNull()) |
---|
361 | { |
---|
362 | QToolTip::showText(event->screenPos(), tr("Go to page %1.").arg(link->page)); |
---|
363 | } |
---|
364 | else |
---|
365 | { |
---|
366 | QToolTip::showText(event->screenPos(), tr("Go to page %1 of file '%2'.").arg(link->page).arg(link->urlOrFileName)); |
---|
367 | } |
---|
368 | |
---|
369 | return; |
---|
370 | } |
---|
371 | else if(!link->urlOrFileName.isNull() && !presentationMode()) |
---|
372 | { |
---|
373 | setCursor(Qt::PointingHandCursor); |
---|
374 | QToolTip::showText(event->screenPos(), tr("Open '%1'.").arg(link->urlOrFileName)); |
---|
375 | |
---|
376 | return; |
---|
377 | } |
---|
378 | } |
---|
379 | } |
---|
380 | |
---|
381 | if(presentationMode()) |
---|
382 | { |
---|
383 | unsetCursor(); |
---|
384 | QToolTip::hideText(); |
---|
385 | |
---|
386 | return; |
---|
387 | } |
---|
388 | |
---|
389 | // annotations |
---|
390 | |
---|
391 | foreach(const Model::Annotation* annotation, m_annotations) |
---|
392 | { |
---|
393 | if(m_normalizedTransform.mapRect(annotation->boundary()).contains(event->pos())) |
---|
394 | { |
---|
395 | setCursor(Qt::PointingHandCursor); |
---|
396 | QToolTip::showText(event->screenPos(), annotation->contents()); |
---|
397 | |
---|
398 | return; |
---|
399 | } |
---|
400 | } |
---|
401 | |
---|
402 | // form fields |
---|
403 | |
---|
404 | foreach(const Model::FormField* formField, m_formFields) |
---|
405 | { |
---|
406 | if(m_normalizedTransform.mapRect(formField->boundary()).contains(event->pos())) |
---|
407 | { |
---|
408 | setCursor(Qt::PointingHandCursor); |
---|
409 | QToolTip::showText(event->screenPos(), tr("Edit form field '%1'.").arg(formField->name())); |
---|
410 | |
---|
411 | return; |
---|
412 | } |
---|
413 | } |
---|
414 | |
---|
415 | unsetCursor(); |
---|
416 | QToolTip::hideText(); |
---|
417 | } |
---|
418 | } |
---|
419 | |
---|
420 | void PageItem::hoverLeaveEvent(QGraphicsSceneHoverEvent*) |
---|
421 | { |
---|
422 | } |
---|
423 | |
---|
424 | void PageItem::mousePressEvent(QGraphicsSceneMouseEvent* event) |
---|
425 | { |
---|
426 | const Qt::KeyboardModifiers copyToClipboardModifiers = s_settings->pageItem().copyToClipboardModifiers(); |
---|
427 | const Qt::KeyboardModifiers addAnnotationModifiers = s_settings->pageItem().addAnnotationModifiers(); |
---|
428 | const Qt::KeyboardModifiers zoomToSelectionModifiers = s_settings->pageItem().zoomToSelectionModifiers(); |
---|
429 | |
---|
430 | const bool copyToClipboardModifiersActive = event->modifiers() == copyToClipboardModifiers || ((event->buttons() & copyToClipboardModifiers) != 0); |
---|
431 | const bool addAnnotationModifiersActive = event->modifiers() == addAnnotationModifiers || ((event->buttons() & addAnnotationModifiers) != 0); |
---|
432 | const bool zoomToSelectionModifiersActive = event->modifiers() == zoomToSelectionModifiers || ((event->buttons() & zoomToSelectionModifiers) != 0); |
---|
433 | |
---|
434 | // rubber band |
---|
435 | |
---|
436 | if(m_rubberBandMode == ModifiersMode && !presentationMode() |
---|
437 | && (copyToClipboardModifiersActive || addAnnotationModifiersActive || zoomToSelectionModifiersActive) |
---|
438 | && event->button() == Qt::LeftButton) |
---|
439 | { |
---|
440 | setCursor(Qt::CrossCursor); |
---|
441 | |
---|
442 | if(copyToClipboardModifiersActive) |
---|
443 | { |
---|
444 | m_rubberBandMode = CopyToClipboardMode; |
---|
445 | } |
---|
446 | else if(addAnnotationModifiersActive) |
---|
447 | { |
---|
448 | m_rubberBandMode = AddAnnotationMode; |
---|
449 | } |
---|
450 | else if(zoomToSelectionModifiersActive) |
---|
451 | { |
---|
452 | m_rubberBandMode = ZoomToSelectionMode; |
---|
453 | } |
---|
454 | } |
---|
455 | |
---|
456 | if(m_rubberBandMode != ModifiersMode) |
---|
457 | { |
---|
458 | m_rubberBand = QRectF(event->pos(), QSizeF()); |
---|
459 | |
---|
460 | emit rubberBandStarted(); |
---|
461 | |
---|
462 | update(); |
---|
463 | |
---|
464 | event->accept(); |
---|
465 | return; |
---|
466 | } |
---|
467 | |
---|
468 | if(event->modifiers() == Qt::NoModifier |
---|
469 | && (event->button() == Qt::LeftButton || event->button() == Qt::MidButton)) |
---|
470 | { |
---|
471 | // links |
---|
472 | |
---|
473 | foreach(const Model::Link* link, m_links) |
---|
474 | { |
---|
475 | if(m_normalizedTransform.map(link->boundary).contains(event->pos())) |
---|
476 | { |
---|
477 | unsetCursor(); |
---|
478 | |
---|
479 | if(link->page != -1 && (link->urlOrFileName.isNull() || !presentationMode())) |
---|
480 | { |
---|
481 | const bool newTab = event->button() == Qt::MidButton; |
---|
482 | |
---|
483 | if(link->urlOrFileName.isNull()) |
---|
484 | { |
---|
485 | emit linkClicked(newTab, link->page, link->left, link->top); |
---|
486 | } |
---|
487 | else |
---|
488 | { |
---|
489 | emit linkClicked(newTab, link->urlOrFileName, link->page); |
---|
490 | } |
---|
491 | |
---|
492 | event->accept(); |
---|
493 | return; |
---|
494 | } |
---|
495 | else if(!link->urlOrFileName.isNull() && !presentationMode()) |
---|
496 | { |
---|
497 | emit linkClicked(link->urlOrFileName); |
---|
498 | |
---|
499 | event->accept(); |
---|
500 | return; |
---|
501 | } |
---|
502 | } |
---|
503 | } |
---|
504 | |
---|
505 | if(event->button() == Qt::MidButton || presentationMode()) |
---|
506 | { |
---|
507 | event->ignore(); |
---|
508 | return; |
---|
509 | } |
---|
510 | |
---|
511 | // annotations |
---|
512 | |
---|
513 | foreach(Model::Annotation* annotation, m_annotations) |
---|
514 | { |
---|
515 | if(m_normalizedTransform.mapRect(annotation->boundary()).contains(event->pos())) |
---|
516 | { |
---|
517 | unsetCursor(); |
---|
518 | |
---|
519 | showAnnotationOverlay(annotation); |
---|
520 | |
---|
521 | event->accept(); |
---|
522 | return; |
---|
523 | } |
---|
524 | } |
---|
525 | |
---|
526 | hideAnnotationOverlay(); |
---|
527 | |
---|
528 | // form fields |
---|
529 | |
---|
530 | foreach(Model::FormField* formField, m_formFields) |
---|
531 | { |
---|
532 | if(m_normalizedTransform.mapRect(formField->boundary()).contains(event->pos())) |
---|
533 | { |
---|
534 | unsetCursor(); |
---|
535 | |
---|
536 | showFormFieldOverlay(formField); |
---|
537 | |
---|
538 | event->accept(); |
---|
539 | return; |
---|
540 | } |
---|
541 | } |
---|
542 | |
---|
543 | hideFormFieldOverlay(); |
---|
544 | } |
---|
545 | |
---|
546 | event->ignore(); |
---|
547 | } |
---|
548 | |
---|
549 | void PageItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event) |
---|
550 | { |
---|
551 | if(!m_rubberBand.isNull()) |
---|
552 | { |
---|
553 | if(m_boundingRect.contains(event->pos())) |
---|
554 | { |
---|
555 | m_rubberBand.setBottomRight(event->pos()); |
---|
556 | |
---|
557 | update(); |
---|
558 | |
---|
559 | event->accept(); |
---|
560 | return; |
---|
561 | } |
---|
562 | } |
---|
563 | |
---|
564 | event->ignore(); |
---|
565 | } |
---|
566 | |
---|
567 | void PageItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event) |
---|
568 | { |
---|
569 | if(!m_rubberBand.isNull()) |
---|
570 | { |
---|
571 | unsetCursor(); |
---|
572 | |
---|
573 | m_rubberBand = m_rubberBand.normalized(); |
---|
574 | |
---|
575 | if(m_rubberBandMode == CopyToClipboardMode) |
---|
576 | { |
---|
577 | copyToClipboard(event->screenPos()); |
---|
578 | } |
---|
579 | else if(m_rubberBandMode == AddAnnotationMode) |
---|
580 | { |
---|
581 | addAnnotation(event->screenPos()); |
---|
582 | } |
---|
583 | else if(m_rubberBandMode == ZoomToSelectionMode) |
---|
584 | { |
---|
585 | emit zoomToSelection(m_index + 1, m_normalizedTransform.inverted().mapRect(m_rubberBand)); |
---|
586 | } |
---|
587 | |
---|
588 | m_rubberBandMode = ModifiersMode; |
---|
589 | m_rubberBand = QRectF(); |
---|
590 | |
---|
591 | emit rubberBandFinished(); |
---|
592 | |
---|
593 | update(); |
---|
594 | |
---|
595 | event->accept(); |
---|
596 | return; |
---|
597 | } |
---|
598 | |
---|
599 | event->ignore(); |
---|
600 | } |
---|
601 | |
---|
602 | void PageItem::contextMenuEvent(QGraphicsSceneContextMenuEvent* event) |
---|
603 | { |
---|
604 | if(event->reason() == QGraphicsSceneContextMenuEvent::Mouse && modifiersUseMouseButton(s_settings, Qt::RightButton)) |
---|
605 | { |
---|
606 | event->accept(); |
---|
607 | return; |
---|
608 | } |
---|
609 | |
---|
610 | if(presentationMode()) |
---|
611 | { |
---|
612 | event->ignore(); |
---|
613 | return; |
---|
614 | } |
---|
615 | |
---|
616 | foreach(Model::Link* link, m_links) |
---|
617 | { |
---|
618 | if(m_normalizedTransform.map(link->boundary).contains(event->pos())) |
---|
619 | { |
---|
620 | unsetCursor(); |
---|
621 | |
---|
622 | showLinkContextMenu(link, event->screenPos()); |
---|
623 | |
---|
624 | event->accept(); |
---|
625 | return; |
---|
626 | } |
---|
627 | } |
---|
628 | |
---|
629 | foreach(Model::Annotation* annotation, m_annotations) |
---|
630 | { |
---|
631 | if(m_normalizedTransform.mapRect(annotation->boundary()).contains(event->pos())) |
---|
632 | { |
---|
633 | unsetCursor(); |
---|
634 | |
---|
635 | showAnnotationContextMenu(annotation, event->screenPos()); |
---|
636 | |
---|
637 | event->accept(); |
---|
638 | return; |
---|
639 | } |
---|
640 | } |
---|
641 | |
---|
642 | event->ignore(); |
---|
643 | } |
---|
644 | |
---|
645 | void PageItem::loadInteractiveElements() |
---|
646 | { |
---|
647 | m_links = m_page->links(); |
---|
648 | |
---|
649 | if(!presentationMode()) |
---|
650 | { |
---|
651 | m_annotations = m_page->annotations(); |
---|
652 | |
---|
653 | foreach(const Model::Annotation* annotation, m_annotations) |
---|
654 | { |
---|
655 | connect(annotation, SIGNAL(wasModified()), SIGNAL(wasModified())); |
---|
656 | } |
---|
657 | |
---|
658 | m_formFields = m_page->formFields(); |
---|
659 | |
---|
660 | foreach(const Model::FormField* formField, m_formFields) |
---|
661 | { |
---|
662 | connect(formField, SIGNAL(wasModified()), SIGNAL(wasModified())); |
---|
663 | } |
---|
664 | } |
---|
665 | |
---|
666 | update(); |
---|
667 | } |
---|
668 | |
---|
669 | void PageItem::updateCropRect() |
---|
670 | { |
---|
671 | QRectF cropRect; |
---|
672 | |
---|
673 | if(!useTiling()) |
---|
674 | { |
---|
675 | cropRect = m_tileItems.first()->cropRect(); |
---|
676 | } |
---|
677 | else |
---|
678 | { |
---|
679 | foreach(TileItem* tile, m_tileItems) |
---|
680 | { |
---|
681 | const QRect& tileRect = tile->rect(); |
---|
682 | const QRectF& tileCropRect = tile->cropRect(); |
---|
683 | |
---|
684 | if(tileCropRect.isNull()) |
---|
685 | { |
---|
686 | cropRect = QRectF(); |
---|
687 | break; |
---|
688 | } |
---|
689 | |
---|
690 | const qreal left = (tileRect.left() + tileCropRect.left() * tileRect.width()) / m_boundingRect.width(); |
---|
691 | const qreal top = (tileRect.top() + tileCropRect.top() * tileRect.height()) / m_boundingRect.height(); |
---|
692 | const qreal width = tileCropRect.width() * tileRect.width() / m_boundingRect.width(); |
---|
693 | const qreal height = tileCropRect.height() * tileRect.height() / m_boundingRect.height(); |
---|
694 | |
---|
695 | cropRect = cropRect.united(QRectF(left, top, width, height)); |
---|
696 | } |
---|
697 | } |
---|
698 | |
---|
699 | if(m_cropRect.isNull() && !cropRect.isNull()) |
---|
700 | { |
---|
701 | prepareGeometryChange(); |
---|
702 | |
---|
703 | m_cropRect = cropRect; |
---|
704 | |
---|
705 | emit cropRectChanged(); |
---|
706 | } |
---|
707 | } |
---|
708 | |
---|
709 | inline bool PageItem::presentationMode() const |
---|
710 | { |
---|
711 | return m_paintMode == PresentationMode; |
---|
712 | } |
---|
713 | |
---|
714 | inline bool PageItem::thumbnailMode() const |
---|
715 | { |
---|
716 | return m_paintMode == ThumbnailMode; |
---|
717 | } |
---|
718 | |
---|
719 | bool PageItem::useTiling() const |
---|
720 | { |
---|
721 | return m_paintMode != ThumbnailMode && s_settings->pageItem().useTiling(); |
---|
722 | } |
---|
723 | |
---|
724 | void PageItem::copyToClipboard(const QPoint& screenPos) |
---|
725 | { |
---|
726 | QMenu menu; |
---|
727 | |
---|
728 | QAction* copyTextAction = menu.addAction(tr("Copy &text")); |
---|
729 | QAction* selectTextAction = menu.addAction(tr("&Select text")); |
---|
730 | const QAction* copyImageAction = menu.addAction(tr("Copy &image")); |
---|
731 | const QAction* saveImageToFileAction = menu.addAction(tr("Save image to &file...")); |
---|
732 | |
---|
733 | const QString text = m_page->text(m_transform.inverted().mapRect(m_rubberBand)); |
---|
734 | |
---|
735 | copyTextAction->setVisible(!text.isEmpty()); |
---|
736 | selectTextAction->setVisible(!text.isEmpty() && QApplication::clipboard()->supportsSelection()); |
---|
737 | |
---|
738 | const QAction* action = menu.exec(screenPos); |
---|
739 | |
---|
740 | if(action == copyTextAction || action == selectTextAction) |
---|
741 | { |
---|
742 | if(action == copyTextAction) |
---|
743 | { |
---|
744 | QApplication::clipboard()->setText(text); |
---|
745 | } |
---|
746 | else |
---|
747 | { |
---|
748 | QApplication::clipboard()->setText(text, QClipboard::Selection); |
---|
749 | } |
---|
750 | } |
---|
751 | else if(action == copyImageAction || action == saveImageToFileAction) |
---|
752 | { |
---|
753 | const QRect rect = m_rubberBand.translated(-m_boundingRect.topLeft()).toRect(); |
---|
754 | const QImage image = m_page->render(m_renderParam.resolutionX() * m_renderParam.scaleFactor(), |
---|
755 | m_renderParam.resolutionY() * m_renderParam.scaleFactor(), |
---|
756 | m_renderParam.rotation(), rect); |
---|
757 | |
---|
758 | if(!image.isNull()) |
---|
759 | { |
---|
760 | if(action == copyImageAction) |
---|
761 | { |
---|
762 | QApplication::clipboard()->setImage(image); |
---|
763 | } |
---|
764 | else if(action == saveImageToFileAction) |
---|
765 | { |
---|
766 | const QString fileName = QFileDialog::getSaveFileName(0, tr("Save image to file"), QDir::homePath(), "Portable network graphics (*.png)"); |
---|
767 | |
---|
768 | if(!image.save(fileName, "PNG")) |
---|
769 | { |
---|
770 | QMessageBox::warning(0, tr("Warning"), tr("Could not save image to file '%1'.").arg(fileName)); |
---|
771 | } |
---|
772 | } |
---|
773 | } |
---|
774 | } |
---|
775 | } |
---|
776 | |
---|
777 | void PageItem::addAnnotation(const QPoint& screenPos) |
---|
778 | { |
---|
779 | if(m_page->canAddAndRemoveAnnotations()) |
---|
780 | { |
---|
781 | QMenu menu; |
---|
782 | |
---|
783 | const QAction* addTextAction = menu.addAction(tr("Add &text")); |
---|
784 | const QAction* addHighlightAction = menu.addAction(tr("Add &highlight")); |
---|
785 | |
---|
786 | const QAction* action = menu.exec(screenPos); |
---|
787 | |
---|
788 | if(action == addTextAction || action == addHighlightAction) |
---|
789 | { |
---|
790 | QRectF boundary = m_normalizedTransform.inverted().mapRect(m_rubberBand); |
---|
791 | |
---|
792 | Model::Annotation* annotation = 0; |
---|
793 | |
---|
794 | if(action == addTextAction) |
---|
795 | { |
---|
796 | boundary.setWidth(24.0 / m_size.width()); |
---|
797 | boundary.setHeight(24.0 / m_size.height()); |
---|
798 | |
---|
799 | annotation = m_page->addTextAnnotation(boundary, s_settings->pageItem().annotationColor()); |
---|
800 | } |
---|
801 | else if(action == addHighlightAction) |
---|
802 | { |
---|
803 | annotation = m_page->addHighlightAnnotation(boundary, s_settings->pageItem().annotationColor()); |
---|
804 | } |
---|
805 | |
---|
806 | m_annotations.append(annotation); |
---|
807 | connect(annotation, SIGNAL(wasModified()), SIGNAL(wasModified())); |
---|
808 | |
---|
809 | refresh(false, true); |
---|
810 | emit wasModified(); |
---|
811 | |
---|
812 | showAnnotationOverlay(annotation); |
---|
813 | } |
---|
814 | } |
---|
815 | } |
---|
816 | |
---|
817 | void PageItem::showLinkContextMenu(Model::Link* link, const QPoint& screenPos) |
---|
818 | { |
---|
819 | if(link->page == -1) |
---|
820 | { |
---|
821 | QMenu menu; |
---|
822 | |
---|
823 | const QAction* copyLinkAddressAction = menu.addAction(tr("&Copy link address")); |
---|
824 | QAction* selectLinkAddressAction = menu.addAction(tr("&Select link address")); |
---|
825 | |
---|
826 | selectLinkAddressAction->setVisible(QApplication::clipboard()->supportsSelection()); |
---|
827 | |
---|
828 | const QAction* action = menu.exec(screenPos); |
---|
829 | |
---|
830 | if(action == copyLinkAddressAction) |
---|
831 | { |
---|
832 | QApplication::clipboard()->setText(link->urlOrFileName); |
---|
833 | } |
---|
834 | else if(action == selectLinkAddressAction) |
---|
835 | { |
---|
836 | QApplication::clipboard()->setText(link->urlOrFileName, QClipboard::Selection); |
---|
837 | } |
---|
838 | } |
---|
839 | } |
---|
840 | |
---|
841 | void PageItem::showAnnotationContextMenu(Model::Annotation* annotation, const QPoint& screenPos) |
---|
842 | { |
---|
843 | if(m_page->canAddAndRemoveAnnotations()) |
---|
844 | { |
---|
845 | QMenu menu; |
---|
846 | |
---|
847 | const QAction* removeAnnotationAction = menu.addAction(tr("&Remove annotation")); |
---|
848 | |
---|
849 | const QAction* action = menu.exec(screenPos); |
---|
850 | |
---|
851 | if(action == removeAnnotationAction) |
---|
852 | { |
---|
853 | m_annotations.removeAll(annotation); |
---|
854 | m_page->removeAnnotation(annotation); |
---|
855 | |
---|
856 | annotation->deleteLater(); |
---|
857 | |
---|
858 | refresh(false, true); |
---|
859 | emit wasModified(); |
---|
860 | } |
---|
861 | } |
---|
862 | } |
---|
863 | |
---|
864 | template< typename Overlay, typename Element > |
---|
865 | void PageItem::showOverlay(Overlay& overlay, const char* hideOverlay, const QList< Element* >& elements, Element* selectedElement) |
---|
866 | { |
---|
867 | foreach(Element* element, elements) |
---|
868 | { |
---|
869 | if(!overlay.contains(element)) |
---|
870 | { |
---|
871 | addProxy(overlay, hideOverlay, element); |
---|
872 | } |
---|
873 | |
---|
874 | if(element == selectedElement) |
---|
875 | { |
---|
876 | overlay.value(element)->widget()->setFocus(); |
---|
877 | } |
---|
878 | } |
---|
879 | } |
---|
880 | |
---|
881 | template< typename Overlay, typename Element > |
---|
882 | void PageItem::addProxy(Overlay& overlay, const char* hideOverlay, Element* element) |
---|
883 | { |
---|
884 | QGraphicsProxyWidget* proxy = new QGraphicsProxyWidget(this); |
---|
885 | proxy->setWidget(element->createWidget()); |
---|
886 | |
---|
887 | #if QT_VERSION >= QT_VERSION_CHECK(4,7,0) |
---|
888 | |
---|
889 | proxy->setAutoFillBackground(true); |
---|
890 | |
---|
891 | #endif // QT_VERSION |
---|
892 | |
---|
893 | overlay.insert(element, proxy); |
---|
894 | setProxyGeometry(element, proxy); |
---|
895 | |
---|
896 | connect(proxy, SIGNAL(visibleChanged()), hideOverlay); |
---|
897 | } |
---|
898 | |
---|
899 | template< typename Overlay > |
---|
900 | void PageItem::hideOverlay(Overlay& overlay, bool deleteLater) |
---|
901 | { |
---|
902 | #if QT_VERSION >= QT_VERSION_CHECK(4,8,0) |
---|
903 | |
---|
904 | Overlay discardedOverlay; |
---|
905 | discardedOverlay.swap(overlay); |
---|
906 | |
---|
907 | #else |
---|
908 | |
---|
909 | Overlay discardedOverlay(overlay); |
---|
910 | overlay = Overlay(); |
---|
911 | |
---|
912 | #endif // QT_VERSION |
---|
913 | |
---|
914 | if(!discardedOverlay.isEmpty()) |
---|
915 | { |
---|
916 | for(typename Overlay::const_iterator i = discardedOverlay.constBegin(); i != discardedOverlay.constEnd(); ++i) |
---|
917 | { |
---|
918 | if(deleteLater) |
---|
919 | { |
---|
920 | i.value()->deleteLater(); |
---|
921 | } |
---|
922 | else |
---|
923 | { |
---|
924 | delete i.value(); |
---|
925 | } |
---|
926 | } |
---|
927 | |
---|
928 | refresh(false, true); |
---|
929 | } |
---|
930 | } |
---|
931 | |
---|
932 | template< typename Overlay > |
---|
933 | void PageItem::updateOverlay(const Overlay& overlay) const |
---|
934 | { |
---|
935 | for(typename Overlay::const_iterator i = overlay.constBegin(); i != overlay.constEnd(); ++i) |
---|
936 | { |
---|
937 | setProxyGeometry(i.key(), i.value()); |
---|
938 | } |
---|
939 | } |
---|
940 | |
---|
941 | void PageItem::setProxyGeometry(Model::Annotation* annotation, QGraphicsProxyWidget* proxy) const |
---|
942 | { |
---|
943 | const QPointF center = m_normalizedTransform.map(annotation->boundary().center()); |
---|
944 | |
---|
945 | qreal x = center.x() - 0.5 * proxy->preferredWidth(); |
---|
946 | qreal y = center.y() - 0.5 * proxy->preferredHeight(); |
---|
947 | qreal width = proxy->preferredWidth(); |
---|
948 | qreal height = proxy->preferredHeight(); |
---|
949 | |
---|
950 | x = qMax(x, m_boundingRect.left() + proxyPadding); |
---|
951 | y = qMax(y, m_boundingRect.top() + proxyPadding); |
---|
952 | |
---|
953 | width = qMin(width, m_boundingRect.right() - proxyPadding - x); |
---|
954 | height = qMin(height, m_boundingRect.bottom() - proxyPadding - y); |
---|
955 | |
---|
956 | proxy->setGeometry(QRectF(x, y, width, height)); |
---|
957 | } |
---|
958 | |
---|
959 | void PageItem::setProxyGeometry(Model::FormField* formField, QGraphicsProxyWidget* proxy) const |
---|
960 | { |
---|
961 | QRectF rect = m_normalizedTransform.mapRect(formField->boundary()); |
---|
962 | |
---|
963 | qreal x = rect.x(); |
---|
964 | qreal y = rect.y(); |
---|
965 | qreal width = rect.width(); |
---|
966 | qreal height = rect.height(); |
---|
967 | |
---|
968 | switch(m_renderParam.rotation()) |
---|
969 | { |
---|
970 | default: |
---|
971 | case RotateBy0: |
---|
972 | proxy->setRotation(0.0); |
---|
973 | break; |
---|
974 | case RotateBy90: |
---|
975 | x += width; |
---|
976 | qSwap(width, height); |
---|
977 | |
---|
978 | proxy->setRotation(90.0); |
---|
979 | break; |
---|
980 | case RotateBy180: |
---|
981 | x += width; |
---|
982 | y += height; |
---|
983 | |
---|
984 | proxy->setRotation(180.0); |
---|
985 | break; |
---|
986 | case RotateBy270: |
---|
987 | y += height; |
---|
988 | qSwap(width, height); |
---|
989 | |
---|
990 | proxy->setRotation(270.0); |
---|
991 | break; |
---|
992 | } |
---|
993 | |
---|
994 | width /= m_renderParam.scaleFactor(); |
---|
995 | height /= m_renderParam.scaleFactor(); |
---|
996 | |
---|
997 | proxy->setScale(m_renderParam.scaleFactor()); |
---|
998 | |
---|
999 | proxy->setGeometry(QRectF(x - proxyPadding, y - proxyPadding, width + proxyPadding, height + proxyPadding)); |
---|
1000 | } |
---|
1001 | |
---|
1002 | void PageItem::prepareGeometry() |
---|
1003 | { |
---|
1004 | m_transform.reset(); |
---|
1005 | |
---|
1006 | m_transform.scale(m_renderParam.resolutionX() * m_renderParam.scaleFactor() / 72.0, |
---|
1007 | m_renderParam.resolutionY() * m_renderParam.scaleFactor() / 72.0); |
---|
1008 | |
---|
1009 | switch(m_renderParam.rotation()) |
---|
1010 | { |
---|
1011 | default: |
---|
1012 | case RotateBy0: |
---|
1013 | break; |
---|
1014 | case RotateBy90: |
---|
1015 | m_transform.rotate(90.0); |
---|
1016 | break; |
---|
1017 | case RotateBy180: |
---|
1018 | m_transform.rotate(180.0); |
---|
1019 | break; |
---|
1020 | case RotateBy270: |
---|
1021 | m_transform.rotate(270.0); |
---|
1022 | break; |
---|
1023 | } |
---|
1024 | |
---|
1025 | m_normalizedTransform = m_transform; |
---|
1026 | m_normalizedTransform.scale(m_size.width(), m_size.height()); |
---|
1027 | |
---|
1028 | |
---|
1029 | m_boundingRect = m_transform.mapRect(QRectF(QPointF(), m_size)); |
---|
1030 | |
---|
1031 | m_boundingRect.setWidth(qRound(m_boundingRect.width())); |
---|
1032 | m_boundingRect.setHeight(qRound(m_boundingRect.height())); |
---|
1033 | |
---|
1034 | |
---|
1035 | prepareTiling(); |
---|
1036 | |
---|
1037 | updateAnnotationOverlay(); |
---|
1038 | updateFormFieldOverlay(); |
---|
1039 | } |
---|
1040 | |
---|
1041 | void PageItem::prepareTiling() |
---|
1042 | { |
---|
1043 | if(!useTiling()) |
---|
1044 | { |
---|
1045 | m_tileItems.first()->setRect(QRect(0, 0, m_boundingRect.width(), m_boundingRect.height())); |
---|
1046 | |
---|
1047 | return; |
---|
1048 | } |
---|
1049 | |
---|
1050 | |
---|
1051 | const qreal pageWidth = m_boundingRect.width(); |
---|
1052 | const qreal pageHeight = m_boundingRect.height(); |
---|
1053 | const qreal pageSize = qMax(pageWidth, pageHeight); |
---|
1054 | |
---|
1055 | int tileSize = s_settings->pageItem().tileSize(); |
---|
1056 | |
---|
1057 | if(tileSize * veryLargeTilesThreshold < pageSize) |
---|
1058 | { |
---|
1059 | tileSize *= 4; |
---|
1060 | } |
---|
1061 | else if(tileSize * largeTilesThreshold < pageSize) |
---|
1062 | { |
---|
1063 | tileSize *= 2; |
---|
1064 | } |
---|
1065 | |
---|
1066 | int tileWidth = pageWidth < pageHeight ? tileSize * pageWidth / pageHeight : tileSize; |
---|
1067 | int tileHeight = pageHeight < pageWidth ? tileSize * pageHeight / pageWidth : tileSize; |
---|
1068 | |
---|
1069 | const int columnCount = qCeil(pageWidth / tileWidth); |
---|
1070 | const int rowCount = qCeil(pageHeight / tileHeight); |
---|
1071 | |
---|
1072 | tileWidth = qCeil(pageWidth / columnCount); |
---|
1073 | tileHeight = qCeil(pageHeight / rowCount); |
---|
1074 | |
---|
1075 | |
---|
1076 | const int newCount = columnCount * rowCount; |
---|
1077 | const int oldCount = m_tileItems.count(); |
---|
1078 | |
---|
1079 | if(oldCount != newCount) |
---|
1080 | { |
---|
1081 | for(int index = newCount; index < oldCount; ++index) |
---|
1082 | { |
---|
1083 | m_tileItems.at(index)->deleteAfterRender(); |
---|
1084 | } |
---|
1085 | |
---|
1086 | m_tileItems.resize(newCount); |
---|
1087 | |
---|
1088 | for(int index = oldCount; index < newCount; ++index) |
---|
1089 | { |
---|
1090 | m_tileItems.replace(index, new TileItem(this)); |
---|
1091 | } |
---|
1092 | |
---|
1093 | foreach(TileItem* tile, m_tileItems) |
---|
1094 | { |
---|
1095 | tile->dropObsoletePixmap(); |
---|
1096 | } |
---|
1097 | } |
---|
1098 | |
---|
1099 | m_exposedTileItems.clear(); |
---|
1100 | |
---|
1101 | |
---|
1102 | for(int column = 0; column < columnCount; ++column) |
---|
1103 | { |
---|
1104 | for(int row = 0; row < rowCount; ++row) |
---|
1105 | { |
---|
1106 | const int left = column > 0 ? column * tileWidth : 0.0; |
---|
1107 | const int top = row > 0 ? row * tileHeight : 0.0; |
---|
1108 | |
---|
1109 | const int width = column < (columnCount - 1) ? tileWidth : pageWidth - left; |
---|
1110 | const int height = row < (rowCount - 1) ? tileHeight : pageHeight - top; |
---|
1111 | |
---|
1112 | m_tileItems.at(column * rowCount + row)->setRect(QRect(left, top, width, height)); |
---|
1113 | } |
---|
1114 | } |
---|
1115 | } |
---|
1116 | |
---|
1117 | inline void PageItem::paintPage(QPainter* painter, const QRectF& exposedRect) const |
---|
1118 | { |
---|
1119 | if(s_settings->pageItem().decoratePages() && !presentationMode()) |
---|
1120 | { |
---|
1121 | // background |
---|
1122 | |
---|
1123 | QColor paperColor = s_settings->pageItem().paperColor(); |
---|
1124 | |
---|
1125 | if(m_renderParam.invertColors()) |
---|
1126 | { |
---|
1127 | paperColor.setRgb(~paperColor.rgb()); |
---|
1128 | } |
---|
1129 | |
---|
1130 | painter->fillRect(m_boundingRect, QBrush(paperColor)); |
---|
1131 | } |
---|
1132 | |
---|
1133 | // tiles |
---|
1134 | |
---|
1135 | if(!useTiling()) |
---|
1136 | { |
---|
1137 | TileItem* tile = m_tileItems.first(); |
---|
1138 | |
---|
1139 | if(tile->paint(painter, m_boundingRect.topLeft())) |
---|
1140 | { |
---|
1141 | tile->dropPixmap(); |
---|
1142 | } |
---|
1143 | } |
---|
1144 | else |
---|
1145 | { |
---|
1146 | const QRectF& translatedExposedRect = exposedRect.translated(-m_boundingRect.topLeft()); |
---|
1147 | |
---|
1148 | foreach(TileItem* tile, m_tileItems) |
---|
1149 | { |
---|
1150 | const bool intersects = translatedExposedRect.intersects(tile->rect()); |
---|
1151 | const bool contains = m_exposedTileItems.contains(tile); |
---|
1152 | |
---|
1153 | if(intersects && !contains) |
---|
1154 | { |
---|
1155 | m_exposedTileItems.insert(tile); |
---|
1156 | } |
---|
1157 | else if(!intersects && contains) |
---|
1158 | { |
---|
1159 | m_exposedTileItems.remove(tile); |
---|
1160 | |
---|
1161 | tile->cancelRender(); |
---|
1162 | } |
---|
1163 | } |
---|
1164 | |
---|
1165 | bool allExposedPainted = true; |
---|
1166 | |
---|
1167 | foreach(TileItem* tile, m_exposedTileItems) |
---|
1168 | { |
---|
1169 | if(!tile->paint(painter, m_boundingRect.topLeft())) |
---|
1170 | { |
---|
1171 | allExposedPainted = false; |
---|
1172 | } |
---|
1173 | } |
---|
1174 | |
---|
1175 | if(allExposedPainted) |
---|
1176 | { |
---|
1177 | foreach(TileItem* tile, m_exposedTileItems) |
---|
1178 | { |
---|
1179 | tile->dropPixmap(); |
---|
1180 | } |
---|
1181 | } |
---|
1182 | } |
---|
1183 | |
---|
1184 | if(s_settings->pageItem().decoratePages() && !presentationMode()) |
---|
1185 | { |
---|
1186 | // border |
---|
1187 | |
---|
1188 | painter->save(); |
---|
1189 | |
---|
1190 | painter->setClipping(false); |
---|
1191 | |
---|
1192 | painter->drawRect(m_renderParam.trimMargins() ? PageItem::boundingRect() : PageItem::uncroppedBoundingRect()); |
---|
1193 | |
---|
1194 | painter->restore(); |
---|
1195 | } |
---|
1196 | } |
---|
1197 | |
---|
1198 | inline void PageItem::paintLinks(QPainter* painter) const |
---|
1199 | { |
---|
1200 | if(s_settings->pageItem().decorateLinks() && !presentationMode() && !m_links.isEmpty()) |
---|
1201 | { |
---|
1202 | painter->save(); |
---|
1203 | |
---|
1204 | painter->setTransform(m_normalizedTransform, true); |
---|
1205 | painter->setPen(QPen(Qt::red, 0.0)); |
---|
1206 | |
---|
1207 | foreach(const Model::Link* link, m_links) |
---|
1208 | { |
---|
1209 | painter->drawPath(link->boundary); |
---|
1210 | } |
---|
1211 | |
---|
1212 | painter->restore(); |
---|
1213 | } |
---|
1214 | } |
---|
1215 | |
---|
1216 | inline void PageItem::paintFormFields(QPainter* painter) const |
---|
1217 | { |
---|
1218 | if(s_settings->pageItem().decorateFormFields() && !presentationMode() && !m_formFields.isEmpty()) |
---|
1219 | { |
---|
1220 | painter->save(); |
---|
1221 | |
---|
1222 | painter->setTransform(m_normalizedTransform, true); |
---|
1223 | painter->setPen(QPen(Qt::blue, 0.0)); |
---|
1224 | |
---|
1225 | foreach(const Model::FormField* formField, m_formFields) |
---|
1226 | { |
---|
1227 | painter->drawRect(formField->boundary()); |
---|
1228 | } |
---|
1229 | |
---|
1230 | painter->restore(); |
---|
1231 | } |
---|
1232 | } |
---|
1233 | |
---|
1234 | inline void PageItem::paintHighlights(QPainter* painter) const |
---|
1235 | { |
---|
1236 | if(!m_highlights.isEmpty()) |
---|
1237 | { |
---|
1238 | painter->save(); |
---|
1239 | |
---|
1240 | painter->setTransform(m_transform, true); |
---|
1241 | painter->setPen(QPen(s_settings->pageItem().highlightColor(), 0.0)); |
---|
1242 | painter->setBrush(QBrush(s_settings->pageItem().highlightColor())); |
---|
1243 | painter->setCompositionMode(QPainter::CompositionMode_Multiply); |
---|
1244 | |
---|
1245 | foreach(const QRectF highlight, m_highlights) |
---|
1246 | { |
---|
1247 | painter->drawRect(highlight.normalized()); |
---|
1248 | } |
---|
1249 | |
---|
1250 | painter->restore(); |
---|
1251 | } |
---|
1252 | } |
---|
1253 | |
---|
1254 | inline void PageItem::paintRubberBand(QPainter* painter) const |
---|
1255 | { |
---|
1256 | if(!m_rubberBand.isNull()) |
---|
1257 | { |
---|
1258 | painter->save(); |
---|
1259 | |
---|
1260 | painter->setPen(QPen(Qt::white, 0.0, Qt::DashLine)); |
---|
1261 | painter->setCompositionMode(QPainter::CompositionMode_Difference); |
---|
1262 | |
---|
1263 | painter->drawRect(m_rubberBand); |
---|
1264 | |
---|
1265 | painter->restore(); |
---|
1266 | } |
---|
1267 | } |
---|
1268 | |
---|
1269 | } // qpdfview |
---|