~ubuntu-branches/debian/jessie/qpdfview/jessie

« back to all changes in this revision

Viewing changes to sources/pageitem.cpp

  • Committer: Package Import Robot
  • Author(s): Benjamin Eltzner
  • Date: 2013-04-04 14:51:58 UTC
  • mto: This revision was merged to the branch mainline in revision 11.
  • Revision ID: package-import@ubuntu.com-20130404145158-22g2noz4b8176o35
Tags: upstream-0.4.1
ImportĀ upstreamĀ versionĀ 0.4.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 
3
 
Copyright 2012 Adam Reichold
 
3
Copyright 2012-2013 Adam Reichold
4
4
 
5
5
This file is part of qpdfview.
6
6
 
21
21
 
22
22
#include "pageitem.h"
23
23
 
24
 
#include "annotationdialog.h"
25
 
#include "formfielddialog.h"
26
 
 
27
 
QCache< PageItem*, QImage > PageItem::s_cache(32 * 1024 * 1024);
 
24
#include <QApplication>
 
25
#include <QClipboard>
 
26
#include <QtConcurrentRun>
 
27
#include <QFileDialog>
 
28
#include <QGraphicsSceneHoverEvent>
 
29
#include <qmath.h>
 
30
#include <QMenu>
 
31
#include <QMessageBox>
 
32
#include <QPainter>
 
33
#include <QTimer>
 
34
#include <QToolTip>
 
35
 
 
36
#include "model.h"
 
37
 
 
38
QCache< PageItem*, QPixmap > PageItem::s_cache(32 * 1024 * 1024);
28
39
 
29
40
bool PageItem::s_decoratePages = true;
30
41
bool PageItem::s_decorateLinks = true;
33
44
QColor PageItem::s_backgroundColor(Qt::darkGray);
34
45
QColor PageItem::s_paperColor(Qt::white);
35
46
 
36
 
bool PageItem::s_invertColors = false;
 
47
Qt::KeyboardModifiers PageItem::s_copyToClipboardModifiers(Qt::ShiftModifier);
 
48
Qt::KeyboardModifiers PageItem::s_addAnnotationModifiers(Qt::ControlModifier);
37
49
 
38
 
Qt::KeyboardModifiers PageItem::s_copyModifiers(Qt::ShiftModifier);
39
 
Qt::KeyboardModifiers PageItem::s_annotateModifiers(Qt::ControlModifier);
 
50
QIcon PageItem::s_progressIcon;
 
51
QIcon PageItem::s_errorIcon;
40
52
 
41
53
int PageItem::cacheSize()
42
54
{
104
116
    }
105
117
}
106
118
 
107
 
bool PageItem::invertColors()
108
 
{
109
 
    return s_invertColors;
110
 
}
111
 
 
112
 
void PageItem::setInvertColors(bool invertColors)
113
 
{
114
 
    s_invertColors = invertColors;
115
 
}
116
 
 
117
 
const Qt::KeyboardModifiers& PageItem::copyModifiers()
118
 
{
119
 
    return s_copyModifiers;
120
 
}
121
 
 
122
 
void PageItem::setCopyModifiers(const Qt::KeyboardModifiers& copyModifiers)
123
 
{
124
 
    s_copyModifiers = copyModifiers;
125
 
}
126
 
 
127
 
const Qt::KeyboardModifiers& PageItem::annotateModifiers()
128
 
{
129
 
    return s_annotateModifiers;
130
 
}
131
 
 
132
 
void PageItem::setAnnotateModifiers(const Qt::KeyboardModifiers& annotateModifiers)
133
 
{
134
 
    s_annotateModifiers = annotateModifiers;
135
 
}
136
 
 
137
 
PageItem::PageItem(QMutex* mutex, Poppler::Page* page, int index, QGraphicsItem* parent) : QGraphicsObject(parent),
138
 
    m_mutex(0),
 
119
const Qt::KeyboardModifiers& PageItem::copyToClipboardModifiers()
 
120
{
 
121
    return s_copyToClipboardModifiers;
 
122
}
 
123
 
 
124
void PageItem::setCopyToClipboardModifiers(const Qt::KeyboardModifiers& copyToClipboardModifiers)
 
125
{
 
126
    s_copyToClipboardModifiers = copyToClipboardModifiers;
 
127
}
 
128
 
 
129
const Qt::KeyboardModifiers& PageItem::addAnnotationModifiers()
 
130
{
 
131
    return s_addAnnotationModifiers;
 
132
}
 
133
 
 
134
void PageItem::setAddAnnotationModifiers(const Qt::KeyboardModifiers& addAnnotationModifiers)
 
135
{
 
136
    s_addAnnotationModifiers = addAnnotationModifiers;
 
137
}
 
138
 
 
139
const QIcon& PageItem::progressIcon()
 
140
{
 
141
    return s_progressIcon;
 
142
}
 
143
 
 
144
void PageItem::setProgressIcon(const QIcon& progressIcon)
 
145
{
 
146
    s_progressIcon = progressIcon;
 
147
}
 
148
 
 
149
const QIcon& PageItem::errorIcon()
 
150
{
 
151
    return s_errorIcon;
 
152
}
 
153
 
 
154
void PageItem::setErrorIcon(const QIcon& errorIcon)
 
155
{
 
156
    s_errorIcon = errorIcon;
 
157
}
 
158
 
 
159
PageItem::PageItem(Model::Page* page, int index, bool presentationMode, QGraphicsItem* parent) : QGraphicsObject(parent),
139
160
    m_page(0),
140
161
    m_index(-1),
141
162
    m_size(),
142
163
    m_links(),
143
164
    m_annotations(),
 
165
    m_presentationMode(presentationMode),
 
166
    m_invertColors(false),
144
167
    m_highlights(),
145
168
    m_rubberBandMode(ModifiersMode),
146
169
    m_rubberBand(),
147
170
    m_physicalDpiX(72),
148
171
    m_physicalDpiY(72),
149
172
    m_scaleFactor(1.0),
150
 
    m_rotation(Poppler::Page::Rotate0),
 
173
    m_rotation(RotateBy0),
151
174
    m_transform(),
152
175
    m_normalizedTransform(),
153
176
    m_boundingRect(),
154
 
    m_image(),
 
177
    m_pixmap(),
155
178
    m_render(0)
156
179
{
157
180
    setAcceptHoverEvents(true);
159
182
    m_render = new QFutureWatcher< void >(this);
160
183
    connect(m_render, SIGNAL(finished()), SLOT(on_render_finished()));
161
184
 
162
 
    connect(this, SIGNAL(imageReady(int,int,qreal,Poppler::Page::Rotation,bool,QImage)), SLOT(on_imageReady(int,int,qreal,Poppler::Page::Rotation,bool,QImage)));
 
185
    connect(this, SIGNAL(imageReady(int,int,qreal,Rotation,bool,bool,QImage)), SLOT(on_imageReady(int,int,qreal,Rotation,bool,bool,QImage)));
163
186
 
164
 
    m_mutex = mutex;
165
187
    m_page = page;
166
188
 
167
189
    m_index = index;
168
 
    m_size = m_page->pageSizeF();
169
 
 
170
 
    foreach(Poppler::Link* link, m_page->links())
171
 
    {
172
 
        if(link->linkType() == Poppler::Link::Goto)
173
 
        {
174
 
            if(!static_cast< Poppler::LinkGoto* >(link)->isExternal())
175
 
            {
176
 
                m_links.append(link);
177
 
                continue;
178
 
            }
179
 
        }
180
 
        else if(link->linkType() == Poppler::Link::Browse)
181
 
        {
182
 
            m_links.append(link);
183
 
            continue;
184
 
        }
185
 
 
186
 
        delete link;
187
 
    }
188
 
 
189
 
    foreach(Poppler::Annotation* annotation, m_page->annotations())
190
 
    {
191
 
        if(annotation->subType() == Poppler::Annotation::AText || annotation->subType() == Poppler::Annotation::AHighlight)
192
 
        {
193
 
            m_annotations.append(annotation);
194
 
            continue;
195
 
        }
196
 
 
197
 
        delete annotation;
198
 
    }
199
 
 
200
 
    foreach(Poppler::FormField* formField, m_page->formFields())
201
 
    {
202
 
        if(!formField->isVisible() || formField->isReadOnly())
203
 
        {
204
 
            delete formField;
205
 
            continue;
206
 
        }
207
 
 
208
 
        switch(formField->type())
209
 
        {
210
 
        default:
211
 
        case Poppler::FormField::FormSignature:
212
 
            delete formField;
213
 
            break;
214
 
        case Poppler::FormField::FormText:
215
 
            switch(static_cast< Poppler::FormFieldText* >(formField)->textType())
216
 
            {
217
 
            default:
218
 
            case Poppler::FormFieldText::FileSelect:
219
 
                delete formField;
220
 
                break;
221
 
            case Poppler::FormFieldText::Normal:
222
 
            case Poppler::FormFieldText::Multiline:
223
 
                m_formFields.append(formField);
224
 
                break;
225
 
            }
226
 
 
227
 
            break;
228
 
        case Poppler::FormField::FormChoice:
229
 
            m_formFields.append(formField);
230
 
            break;
231
 
        case Poppler::FormField::FormButton:
232
 
            switch(static_cast< Poppler::FormFieldButton* >(formField)->buttonType())
233
 
            {
234
 
            default:
235
 
            case Poppler::FormFieldButton::Push:
236
 
                delete formField;
237
 
                break;
238
 
            case Poppler::FormFieldButton::CheckBox:
239
 
            case Poppler::FormFieldButton::Radio:
240
 
                m_formFields.append(formField);
241
 
                break;
242
 
            }
243
 
 
244
 
            break;
245
 
        }
246
 
    }
 
190
    m_size = m_page->size();
 
191
 
 
192
    QTimer::singleShot(0, this, SLOT(loadInteractiveElements()));
247
193
 
248
194
    prepareGeometry();
249
195
}
267
213
    return m_boundingRect;
268
214
}
269
215
 
270
 
void PageItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
 
216
void PageItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget* widget)
271
217
{
272
 
    QImage image;
 
218
    QPixmap pixmap;
273
219
 
274
220
    if(s_cache.contains(this))
275
221
    {
276
 
        image = *s_cache.object(this);
 
222
        pixmap = *s_cache.object(this);
277
223
    }
278
224
    else
279
225
    {
280
 
        if(!m_image.isNull())
 
226
        if(!m_pixmap.isNull())
281
227
        {
282
 
            image = m_image;
283
 
            m_image = QImage();
 
228
            pixmap = m_pixmap;
 
229
            m_pixmap = QPixmap();
284
230
 
285
 
            s_cache.insert(this, new QImage(image), image.byteCount());
 
231
            int cost = pixmap.width() * pixmap.height() * pixmap.depth() / 8;
 
232
            s_cache.insert(this, new QPixmap(pixmap), cost);
286
233
        }
287
234
        else
288
235
        {
292
239
 
293
240
    // page
294
241
 
295
 
    if(s_decoratePages)
 
242
    if(s_decoratePages && !m_presentationMode)
296
243
    {
297
244
        QColor paperColor = s_paperColor;
298
245
 
299
 
        if(s_invertColors)
 
246
        if(m_invertColors)
300
247
        {
301
248
            paperColor.setRgb(~paperColor.rgb());
302
249
        }
303
250
 
304
251
        painter->fillRect(m_boundingRect, QBrush(paperColor));
305
 
 
306
 
        painter->drawImage(m_boundingRect.topLeft(), image);
307
 
 
308
 
        painter->setPen(QPen(s_invertColors ? Qt::white : Qt::black));
 
252
    }
 
253
 
 
254
    if(pixmap.isNull())
 
255
    {
 
256
        qreal extent = qMin(0.1 * m_boundingRect.width(), 0.1 * m_boundingRect.height());
 
257
        QRectF rect(m_boundingRect.left() + 0.01 * m_boundingRect.width(), m_boundingRect.top() + 0.01 * m_boundingRect.height(), extent, extent);
 
258
 
 
259
        s_progressIcon.paint(painter, rect.toRect());
 
260
    }
 
261
    else
 
262
    {
 
263
        painter->drawPixmap(m_boundingRect.topLeft(), pixmap);
 
264
    }
 
265
 
 
266
    if(s_decoratePages && !m_presentationMode)
 
267
    {
 
268
        painter->setPen(QPen(m_invertColors ? Qt::white : Qt::black));
309
269
        painter->drawRect(m_boundingRect);
310
270
    }
311
 
    else
312
 
    {
313
 
        painter->drawImage(m_boundingRect.topLeft(), image);
314
 
    }
315
271
 
316
272
    // links
317
273
 
318
 
    if(s_decorateLinks)
 
274
    if(s_decorateLinks && !m_presentationMode && !m_links.isEmpty())
319
275
    {
320
276
        painter->save();
321
277
 
322
278
        painter->setTransform(m_normalizedTransform, true);
323
279
        painter->setPen(QPen(Qt::red));
324
280
 
325
 
        foreach(Poppler::Link* link, m_links)
 
281
        foreach(Model::Link* link, m_links)
326
282
        {
327
 
            painter->drawRect(link->linkArea().normalized());
 
283
            painter->drawPath(link->boundary);
328
284
        }
329
285
 
330
286
        painter->restore();
332
288
 
333
289
    // form fields
334
290
 
335
 
    if(s_decorateFormFields)
 
291
    if(s_decorateFormFields && !m_presentationMode && !m_formFields.isEmpty())
336
292
    {
337
293
        painter->save();
338
294
 
339
295
        painter->setTransform(m_normalizedTransform, true);
340
296
        painter->setPen(QPen(Qt::blue));
341
297
 
342
 
        foreach(Poppler::FormField* formField, m_formFields)
 
298
        foreach(Model::FormField* formField, m_formFields)
343
299
        {
344
 
            painter->drawRect(formField->rect().normalized());
 
300
            painter->drawRect(formField->boundary());
345
301
        }
346
302
 
347
303
        painter->restore();
349
305
 
350
306
    // highlights
351
307
 
352
 
    painter->save();
353
 
 
354
 
    painter->setTransform(m_transform, true);
355
 
 
356
 
    QColor highlightColor = QApplication::palette().color(QPalette::Highlight);
357
 
 
358
 
    highlightColor.setAlpha(127);
359
 
 
360
 
    foreach(QRectF highlight, m_highlights)
 
308
    if(!m_highlights.isEmpty())
361
309
    {
362
 
        painter->fillRect(highlight.normalized(), QBrush(highlightColor));
 
310
        painter->save();
 
311
 
 
312
        painter->setTransform(m_transform, true);
 
313
 
 
314
        QColor highlightColor = widget->palette().color(QPalette::Highlight);
 
315
 
 
316
        highlightColor.setAlpha(127);
 
317
 
 
318
        foreach(QRectF highlight, m_highlights)
 
319
        {
 
320
            painter->fillRect(highlight.normalized(), QBrush(highlightColor));
 
321
        }
 
322
 
 
323
        painter->restore();
363
324
    }
364
325
 
365
 
    painter->restore();
366
 
 
367
326
    // rubber band
368
327
 
369
328
    if(!m_rubberBand.isNull())
370
329
    {
371
330
        QPen pen;
372
 
        pen.setColor(s_invertColors ? Qt::white : Qt::black);
 
331
        pen.setColor(m_invertColors ? Qt::white : Qt::black);
373
332
        pen.setStyle(Qt::DashLine);
374
333
 
375
334
        painter->setPen(pen);
387
346
    return m_size;
388
347
}
389
348
 
 
349
bool PageItem::invertColors()
 
350
{
 
351
    return m_invertColors;
 
352
}
 
353
 
 
354
void PageItem::setInvertColors(bool invertColors)
 
355
{
 
356
    m_invertColors = invertColors;
 
357
 
 
358
    refresh();
 
359
}
 
360
 
390
361
const QList< QRectF >& PageItem::highlights() const
391
362
{
392
363
    return m_highlights;
404
375
    }
405
376
}
406
377
 
407
 
PageItem::RubberBandMode PageItem::rubberBandMode() const
 
378
RubberBandMode PageItem::rubberBandMode() const
408
379
{
409
380
    return m_rubberBandMode;
410
381
}
411
382
 
412
 
void PageItem::setRubberBandMode(PageItem::RubberBandMode rubberBandMode)
 
383
void PageItem::setRubberBandMode(RubberBandMode rubberBandMode)
413
384
{
414
 
    m_rubberBandMode = rubberBandMode;
 
385
    if(m_rubberBandMode != rubberBandMode && rubberBandMode >= 0 && rubberBandMode < NumberOfRubberBandModes)
 
386
    {
 
387
        m_rubberBandMode = rubberBandMode;
415
388
 
416
 
    if(m_rubberBandMode == ModifiersMode)
417
 
    {
418
 
        unsetCursor();
419
 
    }
420
 
    else
421
 
    {
422
 
        setCursor(Qt::CrossCursor);
 
389
        if(m_rubberBandMode == ModifiersMode)
 
390
        {
 
391
            unsetCursor();
 
392
        }
 
393
        else
 
394
        {
 
395
            setCursor(Qt::CrossCursor);
 
396
        }
423
397
    }
424
398
}
425
399
 
435
409
 
436
410
void PageItem::setPhysicalDpi(int physicalDpiX, int physicalDpiY)
437
411
{
438
 
    if(m_physicalDpiX != physicalDpiX || m_physicalDpiY != physicalDpiY)
 
412
    if((m_physicalDpiX != physicalDpiX || m_physicalDpiY != physicalDpiY) && physicalDpiX > 0 && physicalDpiY > 0)
439
413
    {
440
414
        refresh();
441
415
 
454
428
 
455
429
void PageItem::setScaleFactor(qreal scaleFactor)
456
430
{
457
 
    if(m_scaleFactor != scaleFactor)
 
431
    if(m_scaleFactor != scaleFactor && scaleFactor > 0.0)
458
432
    {
459
433
        refresh();
460
434
 
465
439
    }
466
440
}
467
441
 
468
 
Poppler::Page::Rotation PageItem::rotation() const
 
442
Rotation PageItem::rotation() const
469
443
{
470
444
    return m_rotation;
471
445
}
472
446
 
473
 
void PageItem::setRotation(Poppler::Page::Rotation rotation)
 
447
void PageItem::setRotation(Rotation rotation)
474
448
{
475
 
    if(m_rotation != rotation)
 
449
    if(m_rotation != rotation && rotation >= 0 && rotation < NumberOfDirections)
476
450
    {
477
451
        refresh();
478
452
 
511
485
 
512
486
void PageItem::startRender(bool prefetch)
513
487
{
 
488
    if(prefetch && s_cache.contains(this))
 
489
    {
 
490
        return;
 
491
    }
 
492
 
514
493
    if(!m_render->isRunning())
515
494
    {
516
 
        m_render->setFuture(QtConcurrent::run(this, &PageItem::render, m_physicalDpiX, m_physicalDpiY, m_scaleFactor, m_rotation, prefetch));
 
495
        m_render->setFuture(QtConcurrent::run(this, &PageItem::render, RenderOptions(m_physicalDpiX, m_physicalDpiY, m_scaleFactor, m_rotation, m_invertColors, prefetch)));
517
496
    }
518
497
}
519
498
 
521
500
{
522
501
    m_render->cancel();
523
502
 
524
 
    m_image = QImage();
 
503
    m_pixmap = QPixmap();
525
504
}
526
505
 
527
506
void PageItem::on_render_finished()
529
508
    update();
530
509
}
531
510
 
532
 
void PageItem::on_imageReady(int physicalDpiX, int physicalDpiY, qreal scaleFactor, Poppler::Page::Rotation rotation, bool prefetch, QImage image)
 
511
void PageItem::on_imageReady(int physicalDpiX, int physicalDpiY, qreal scaleFactor, Rotation rotation, bool invertColors, bool prefetch, QImage image)
533
512
{
534
 
    if(m_physicalDpiX != physicalDpiX || m_physicalDpiY != physicalDpiY || !qFuzzyCompare(m_scaleFactor, scaleFactor) || m_rotation != rotation)
 
513
    if(m_physicalDpiX != physicalDpiX || m_physicalDpiY != physicalDpiY || !qFuzzyCompare(m_scaleFactor, scaleFactor) || m_rotation != rotation || m_invertColors != invertColors)
535
514
    {
536
515
        return;
537
516
    }
538
517
 
539
 
    if(s_invertColors)
 
518
    if(image.isNull())
540
519
    {
541
 
        image.invertPixels();
 
520
        qreal extent = qMin(0.1 * m_boundingRect.width(), 0.1 * m_boundingRect.height());
 
521
        QRectF rect(0.01 * m_boundingRect.width(), 0.01 * m_boundingRect.height(), extent, extent);
 
522
 
 
523
        image = QImage(qFloor(0.01 * m_boundingRect.width() + extent), qFloor(0.01 * m_boundingRect.height() + extent), QImage::Format_ARGB32);
 
524
        image.fill(Qt::transparent);
 
525
 
 
526
        QPainter painter(&image);
 
527
        s_errorIcon.paint(&painter, rect.toRect());
542
528
    }
543
529
 
544
530
    if(prefetch)
545
531
    {
546
 
        s_cache.insert(this, new QImage(image), image.byteCount());
 
532
        QPixmap pixmap = QPixmap::fromImage(image);
 
533
 
 
534
        int cost = pixmap.width() * pixmap.height() * pixmap.depth() / 8;
 
535
        s_cache.insert(this, new QPixmap(pixmap), cost);
547
536
    }
548
537
    else
549
538
    {
550
539
        if(!m_render->isCanceled())
551
540
        {
552
 
            m_image = image;
 
541
            m_pixmap = QPixmap::fromImage(image);
553
542
        }
554
543
    }
555
544
}
564
553
    {
565
554
        // links
566
555
 
567
 
        foreach(Poppler::Link* link, m_links)
 
556
        foreach(Model::Link* link, m_links)
568
557
        {
569
 
            if(m_normalizedTransform.mapRect(link->linkArea().normalized()).contains(event->pos()))
 
558
            if(m_normalizedTransform.map(link->boundary).contains(event->pos()))
570
559
            {
571
 
                if(link->linkType() == Poppler::Link::Goto)
 
560
                if(link->page != -1 && (link->urlOrFileName.isNull() || !m_presentationMode))
572
561
                {
573
562
                    setCursor(Qt::PointingHandCursor);
574
 
                    QToolTip::showText(event->screenPos(), tr("Go to page %1.").arg(static_cast< Poppler::LinkGoto* >(link)->destination().pageNumber()));
 
563
 
 
564
                    if(link->urlOrFileName.isNull())
 
565
                    {
 
566
                        QToolTip::showText(event->screenPos(), tr("Go to page %1.").arg(link->page));
 
567
                    }
 
568
                    else
 
569
                    {
 
570
                        QToolTip::showText(event->screenPos(), tr("Go to page %1 of file '%2'.").arg(link->page).arg(link->urlOrFileName));
 
571
                    }
575
572
 
576
573
                    return;
577
574
                }
578
 
                else if(link->linkType() == Poppler::Link::Browse)
 
575
                else if(!link->urlOrFileName.isNull() && !m_presentationMode)
579
576
                {
580
577
                    setCursor(Qt::PointingHandCursor);
581
 
                    QToolTip::showText(event->screenPos(), tr("Open %1.").arg(static_cast< Poppler::LinkBrowse* >(link)->url()));
 
578
                    QToolTip::showText(event->screenPos(), tr("Open '%1'.").arg(link->urlOrFileName));
582
579
 
583
580
                    return;
584
581
                }
585
582
            }
586
583
        }
587
584
 
 
585
        if(m_presentationMode)
 
586
        {
 
587
            unsetCursor();
 
588
            QToolTip::hideText();
 
589
            return;
 
590
        }
 
591
 
588
592
        // annotations
589
593
 
590
 
        foreach(Poppler::Annotation* annotation, m_annotations)
 
594
        foreach(Model::Annotation* annotation, m_annotations)
591
595
        {
592
 
            if(m_normalizedTransform.mapRect(annotation->boundary().normalized()).contains(event->pos()))
 
596
            if(m_normalizedTransform.mapRect(annotation->boundary()).contains(event->pos()))
593
597
            {
594
598
                setCursor(Qt::PointingHandCursor);
595
599
                QToolTip::showText(event->screenPos(), annotation->contents());
600
604
 
601
605
        // form fields
602
606
 
603
 
        foreach(Poppler::FormField* formField, m_formFields)
 
607
        foreach(Model::FormField* formField, m_formFields)
604
608
        {
605
 
            if(m_normalizedTransform.mapRect(formField->rect().normalized()).contains(event->pos()))
 
609
            if(m_normalizedTransform.mapRect(formField->boundary()).contains(event->pos()))
606
610
            {
607
611
                setCursor(Qt::PointingHandCursor);
608
612
                QToolTip::showText(event->screenPos(), tr("Edit form field '%1'.").arg(formField->name()));
624
628
{
625
629
    // rubber band
626
630
 
627
 
    if(m_rubberBandMode == ModifiersMode && (event->modifiers() == s_copyModifiers || event->modifiers() == s_annotateModifiers) && event->button() == Qt::LeftButton)
 
631
    if(m_rubberBandMode == ModifiersMode && (event->modifiers() == s_copyToClipboardModifiers || event->modifiers() == s_addAnnotationModifiers) && event->button() == Qt::LeftButton && !m_presentationMode)
628
632
    {
629
633
        setCursor(Qt::CrossCursor);
630
634
 
631
 
        if(event->modifiers() == s_copyModifiers)
 
635
        if(event->modifiers() == s_copyToClipboardModifiers)
632
636
        {
633
637
            m_rubberBandMode = CopyToClipboardMode;
634
638
        }
635
 
        else if(event->modifiers() == s_annotateModifiers)
 
639
        else if(event->modifiers() == s_addAnnotationModifiers)
636
640
        {
637
641
            m_rubberBandMode = AddAnnotationMode;
638
642
        }
654
658
    {
655
659
        // links
656
660
 
657
 
        foreach(Poppler::Link* link, m_links)
 
661
        foreach(Model::Link* link, m_links)
658
662
        {
659
 
            if(m_normalizedTransform.mapRect(link->linkArea().normalized()).contains(event->pos()))
 
663
            if(m_normalizedTransform.map(link->boundary).contains(event->pos()))
660
664
            {
661
665
                unsetCursor();
662
666
 
663
 
                if(link->linkType() == Poppler::Link::Goto)
 
667
                if(link->page != -1 && (link->urlOrFileName.isNull() || !m_presentationMode))
664
668
                {
665
 
                    Poppler::LinkGoto* linkGoto = static_cast< Poppler::LinkGoto* >(link);
666
 
 
667
 
                    int page = linkGoto->destination().pageNumber();
668
 
                    qreal left = linkGoto->destination().isChangeLeft() ? linkGoto->destination().left() : 0.0;
669
 
                    qreal top = linkGoto->destination().isChangeTop() ? linkGoto->destination().top() : 0.0;
670
 
 
671
 
                    emit linkClicked(page, left, top);
 
669
                    if(link->urlOrFileName.isNull())
 
670
                    {
 
671
                        emit linkClicked(link->page, link->left, link->top);
 
672
                    }
 
673
                    else
 
674
                    {
 
675
                        emit linkClicked(link->urlOrFileName, link->page);
 
676
                    }
672
677
 
673
678
                    event->accept();
674
679
                    return;
675
680
                }
676
 
                else if(link->linkType() == Poppler::Link::Browse)
 
681
                else if(!link->urlOrFileName.isNull() && !m_presentationMode)
677
682
                {
678
 
                    emit linkClicked(static_cast< Poppler::LinkBrowse* >(link)->url());
 
683
                    emit linkClicked(link->urlOrFileName);
679
684
 
680
685
                    event->accept();
681
686
                    return;
683
688
            }
684
689
        }
685
690
 
 
691
        if(m_presentationMode)
 
692
        {
 
693
            event->ignore();
 
694
            return;
 
695
        }
 
696
 
686
697
        // annotations
687
698
 
688
 
        foreach(Poppler::Annotation* annotation, m_annotations)
 
699
        foreach(Model::Annotation* annotation, m_annotations)
689
700
        {
690
 
            if(m_normalizedTransform.mapRect(annotation->boundary().normalized()).contains(event->pos()))
 
701
            if(m_normalizedTransform.mapRect(annotation->boundary()).contains(event->pos()))
691
702
            {
692
703
                unsetCursor();
693
704
 
700
711
 
701
712
        // form fields
702
713
 
703
 
        foreach(Poppler::FormField* formField, m_formFields)
 
714
        foreach(Model::FormField* formField, m_formFields)
704
715
        {
705
 
            if(m_normalizedTransform.mapRect(formField->rect().normalized()).contains(event->pos()))
 
716
            if(m_normalizedTransform.mapRect(formField->boundary()).contains(event->pos()))
706
717
            {
707
718
                unsetCursor();
708
719
 
731
742
            m_rubberBand.setBottomRight(event->pos());
732
743
 
733
744
            update();
 
745
 
 
746
            event->accept();
 
747
            return;
734
748
        }
735
749
    }
 
750
 
 
751
    event->ignore();
736
752
}
737
753
 
738
754
void PageItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
768
784
 
769
785
void PageItem::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
770
786
{
771
 
    foreach(Poppler::Annotation* annotation, m_annotations)
772
 
    {
773
 
        if(m_normalizedTransform.mapRect(annotation->boundary().normalized()).contains(event->pos()))
 
787
    if(m_presentationMode)
 
788
    {
 
789
        event->ignore();
 
790
        return;
 
791
    }
 
792
 
 
793
    foreach(Model::Annotation* annotation, m_annotations)
 
794
    {
 
795
        if(m_normalizedTransform.mapRect(annotation->boundary()).contains(event->pos()))
774
796
        {
775
797
            unsetCursor();
776
798
 
784
806
    event->ignore();
785
807
}
786
808
 
 
809
void PageItem::loadInteractiveElements()
 
810
{
 
811
    m_links = m_page->links();
 
812
 
 
813
    if(!m_presentationMode)
 
814
    {
 
815
        m_annotations = m_page->annotations();
 
816
        m_formFields = m_page->formFields();
 
817
    }
 
818
 
 
819
    update();
 
820
}
 
821
 
787
822
void PageItem::copyToClipboard(const QPoint& screenPos)
788
823
{
789
 
    QMenu* menu = new QMenu();
790
 
 
791
 
    QAction* copyTextAction = menu->addAction(tr("Copy &text"));
792
 
    QAction* copyImageAction = menu->addAction(tr("Copy &image"));
793
 
    QAction* saveImageToFileAction = menu->addAction(tr("Save image to &file..."));
794
 
 
795
 
    QAction* action = menu->exec(screenPos);
 
824
    QMenu menu;
 
825
 
 
826
    QAction* copyTextAction = menu.addAction(tr("Copy &text"));
 
827
    QAction* copyImageAction = menu.addAction(tr("Copy &image"));
 
828
    QAction* saveImageToFileAction = menu.addAction(tr("Save image to &file..."));
 
829
 
 
830
    QAction* action = menu.exec(screenPos);
796
831
 
797
832
    if(action == copyTextAction)
798
833
    {
799
 
        QString text;
800
 
 
801
 
        m_mutex->lock();
802
 
 
803
 
        text = m_page->text(m_transform.inverted().mapRect(m_rubberBand));
804
 
 
805
 
        m_mutex->unlock();
 
834
        QString text = m_page->text(m_transform.inverted().mapRect(m_rubberBand));
806
835
 
807
836
        if(!text.isEmpty())
808
837
        {
813
842
    {
814
843
        QImage image;
815
844
 
816
 
        m_mutex->lock();
817
 
 
818
 
        switch(m_rotation)
819
 
        {
820
 
        case Poppler::Page::Rotate0:
821
 
        case Poppler::Page::Rotate90:
822
 
            image = m_page->renderToImage(m_scaleFactor * m_physicalDpiX, m_scaleFactor * m_physicalDpiY, m_rubberBand.x(), m_rubberBand.y(), m_rubberBand.width(), m_rubberBand.height(), m_rotation);
823
 
            break;
824
 
        case Poppler::Page::Rotate180:
825
 
        case Poppler::Page::Rotate270:
826
 
            image = m_page->renderToImage(m_scaleFactor * m_physicalDpiY, m_scaleFactor * m_physicalDpiX, m_rubberBand.x(), m_rubberBand.y(), m_rubberBand.width(), m_rubberBand.height(), m_rotation);
827
 
            break;
828
 
        }
829
 
 
830
 
        m_mutex->unlock();
 
845
        if(s_cache.contains(this))
 
846
        {
 
847
            image = s_cache.object(this)->copy(m_rubberBand.translated(-m_boundingRect.topLeft()).toRect()).toImage();
 
848
        }
 
849
        else
 
850
        {
 
851
            image = m_page->render(m_physicalDpiX * m_scaleFactor,  m_scaleFactor * m_physicalDpiY, m_rotation, m_rubberBand.translated(-m_boundingRect.topLeft()).toRect());
 
852
        }
831
853
 
832
854
        if(!image.isNull())
833
855
        {
846
868
            }
847
869
        }
848
870
    }
849
 
 
850
 
    delete menu;
851
871
}
852
872
 
853
873
void PageItem::addAnnotation(const QPoint& screenPos)
854
874
{
855
 
#ifdef HAS_POPPLER_20
856
 
 
857
 
    QMenu* menu = new QMenu();
858
 
 
859
 
    QAction* addTextAction = menu->addAction(tr("Add &text"));
860
 
    QAction* addHighlightAction = menu->addAction(tr("Add &highlight"));
861
 
 
862
 
    QAction* action = menu->exec(screenPos);
863
 
 
864
 
    if(action == addTextAction || action == addHighlightAction)
865
 
    {
866
 
        QRectF boundary = m_normalizedTransform.inverted().mapRect(m_rubberBand);
867
 
 
868
 
        Poppler::Annotation::Style style;
869
 
        style.setColor(Qt::yellow);
870
 
 
871
 
        Poppler::Annotation::Popup popup;
872
 
        popup.setFlags(Poppler::Annotation::Hidden | Poppler::Annotation::ToggleHidingOnMouse);
873
 
 
874
 
        Poppler::Annotation* annotation = 0;
875
 
 
876
 
        if(action == addTextAction)
877
 
        {
878
 
            boundary.setWidth(24.0 / m_size.width());
879
 
            boundary.setHeight(24.0 / m_size.height());
880
 
 
881
 
            annotation = new Poppler::TextAnnotation(Poppler::TextAnnotation::Linked);
882
 
        }
883
 
        else if(action == addHighlightAction)
884
 
        {
885
 
            Poppler::HighlightAnnotation* highlightAnnotation = new Poppler::HighlightAnnotation();
886
 
 
887
 
            Poppler::HighlightAnnotation::Quad quad;
888
 
            quad.points[0] = boundary.topLeft();
889
 
            quad.points[1] = boundary.topRight();
890
 
            quad.points[2] = boundary.bottomRight();
891
 
            quad.points[3] = boundary.bottomLeft();
892
 
 
893
 
            highlightAnnotation->setHighlightQuads(QList< Poppler::HighlightAnnotation::Quad >() << quad);
894
 
 
895
 
            annotation = highlightAnnotation;
896
 
        }
897
 
 
898
 
        annotation->setBoundary(boundary);
899
 
        annotation->setStyle(style);
900
 
        annotation->setPopup(popup);
901
 
 
902
 
        m_mutex->lock();
903
 
 
904
 
        m_annotations.append(annotation);
905
 
        m_page->addAnnotation(annotation);
906
 
 
907
 
        m_mutex->unlock();
908
 
 
909
 
        refresh();
910
 
 
911
 
        editAnnotation(annotation, screenPos);
912
 
    }
913
 
 
914
 
    delete menu;
915
 
 
916
 
#else
917
 
 
918
 
    Q_UNUSED(screenPos);
919
 
 
920
 
    QMessageBox::information(0, tr("Information"), tr("Version 0.20.1 or higher of the Poppler library is required to add or remove annotations."));
921
 
 
922
 
#endif // HAS_POPPLER_20
923
 
}
924
 
 
925
 
void PageItem::removeAnnotation(Poppler::Annotation* annotation, const QPoint& screenPos)
926
 
{
927
 
#ifdef HAS_POPPLER_20
928
 
 
929
 
    QMenu* menu = new QMenu();
930
 
 
931
 
    QAction* removeAnnotationAction = menu->addAction(tr("&Remove annotation"));
932
 
 
933
 
    QAction* action = menu->exec(screenPos);
934
 
 
935
 
    if(action == removeAnnotationAction)
936
 
    {
937
 
        m_mutex->lock();
938
 
 
939
 
        m_annotations.removeAll(annotation);
940
 
        m_page->removeAnnotation(annotation);
941
 
 
942
 
        m_mutex->unlock();
943
 
 
944
 
        refresh();
945
 
    }
946
 
 
947
 
    delete menu;
948
 
 
949
 
#else
950
 
 
951
 
    Q_UNUSED(annotation);
952
 
    Q_UNUSED(screenPos);
953
 
 
954
 
    QMessageBox::information(0, tr("Information"), tr("Version 0.20.1 or higher of the Poppler library is required to add or remove annotations."));
955
 
 
956
 
#endif // HAS_POPPLER_20
957
 
}
958
 
 
959
 
void PageItem::editAnnotation(Poppler::Annotation* annotation, const QPoint& screenPos)
960
 
{
961
 
    AnnotationDialog* annotationDialog = new AnnotationDialog(m_mutex, annotation);
962
 
 
963
 
    annotationDialog->move(screenPos);
964
 
 
965
 
    annotationDialog->setAttribute(Qt::WA_DeleteOnClose);
966
 
    annotationDialog->show();
967
 
}
968
 
 
969
 
void PageItem::editFormField(Poppler::FormField* formField, const QPoint& screenPos)
970
 
{
971
 
    if(formField->type() == Poppler::FormField::FormText || formField->type() == Poppler::FormField::FormChoice)
972
 
    {
973
 
        FormFieldDialog* formFieldDialog = new FormFieldDialog(m_mutex, formField);
974
 
 
975
 
        formFieldDialog->move(screenPos);
976
 
 
977
 
        formFieldDialog->setAttribute(Qt::WA_DeleteOnClose);
978
 
        formFieldDialog->show();
979
 
 
 
875
    if(m_page->canAddAndRemoveAnnotations())
 
876
    {
 
877
        QMenu menu;
 
878
 
 
879
        QAction* addTextAction = menu.addAction(tr("Add &text"));
 
880
        QAction* addHighlightAction = menu.addAction(tr("Add &highlight"));
 
881
 
 
882
        QAction* action = menu.exec(screenPos);
 
883
 
 
884
        if(action == addTextAction || action == addHighlightAction)
 
885
        {
 
886
            QRectF boundary = m_normalizedTransform.inverted().mapRect(m_rubberBand);
 
887
 
 
888
            Model::Annotation* annotation = 0;
 
889
 
 
890
            if(action == addTextAction)
 
891
            {
 
892
                boundary.setWidth(24.0 / m_size.width());
 
893
                boundary.setHeight(24.0 / m_size.height());
 
894
 
 
895
                annotation = m_page->addTextAnnotation(boundary);
 
896
            }
 
897
            else if(action == addHighlightAction)
 
898
            {
 
899
                annotation = m_page->addHighlightAnnotation(boundary);
 
900
            }
 
901
 
 
902
            m_annotations.append(annotation);
 
903
 
 
904
            refresh();
 
905
 
 
906
            editAnnotation(annotation, screenPos);
 
907
        }
 
908
    }
 
909
}
 
910
 
 
911
void PageItem::removeAnnotation(Model::Annotation* annotation, const QPoint& screenPos)
 
912
{
 
913
    if(m_page->canAddAndRemoveAnnotations())
 
914
    {
 
915
        QMenu menu;
 
916
 
 
917
        QAction* removeAnnotationAction = menu.addAction(tr("&Remove annotation"));
 
918
 
 
919
        QAction* action = menu.exec(screenPos);
 
920
 
 
921
        if(action == removeAnnotationAction)
 
922
        {
 
923
            m_annotations.removeAll(annotation);
 
924
            m_page->removeAnnotation(annotation);
 
925
 
 
926
            refresh();
 
927
        }
 
928
    }
 
929
}
 
930
 
 
931
void PageItem::editAnnotation(Model::Annotation* annotation, const QPoint& screenPos)
 
932
{
 
933
    annotation->showDialog(screenPos);
 
934
}
 
935
 
 
936
void PageItem::editFormField(Model::FormField* formField, const QPoint& screenPos)
 
937
{
 
938
    QDialog* formFieldDialog = formField->showDialog(screenPos);
 
939
 
 
940
    if(formFieldDialog != 0)
 
941
    {
980
942
        connect(formFieldDialog, SIGNAL(destroyed()), SLOT(refresh()));
981
943
    }
982
 
    else if(formField->type() == Poppler::FormField::FormButton)
 
944
    else
983
945
    {
984
 
        Poppler::FormFieldButton* formFieldButton = static_cast< Poppler::FormFieldButton* >(formField);
985
 
 
986
 
        formFieldButton->setState(!formFieldButton->state());
987
 
 
988
946
        refresh();
989
947
    }
990
948
}
996
954
 
997
955
    switch(m_rotation)
998
956
    {
999
 
    case Poppler::Page::Rotate0:
 
957
    default:
 
958
    case RotateBy0:
1000
959
        break;
1001
 
    case Poppler::Page::Rotate90:
 
960
    case RotateBy90:
1002
961
        m_transform.rotate(90.0);
1003
962
        m_normalizedTransform.rotate(90.0);
1004
963
        break;
1005
 
    case Poppler::Page::Rotate180:
 
964
    case RotateBy180:
1006
965
        m_transform.rotate(180.0);
1007
966
        m_normalizedTransform.rotate(180.0);
1008
967
        break;
1009
 
    case Poppler::Page::Rotate270:
 
968
    case RotateBy270:
1010
969
        m_transform.rotate(270.0);
1011
970
        m_normalizedTransform.rotate(270.0);
1012
971
        break;
1014
973
 
1015
974
    switch(m_rotation)
1016
975
    {
1017
 
    case Poppler::Page::Rotate0:
1018
 
    case Poppler::Page::Rotate90:
 
976
    default:
 
977
    case RotateBy0:
 
978
    case RotateBy180:
1019
979
        m_transform.scale(m_scaleFactor * m_physicalDpiX / 72.0, m_scaleFactor * m_physicalDpiY / 72.0);
1020
980
        m_normalizedTransform.scale(m_scaleFactor * m_physicalDpiX / 72.0 * m_size.width(), m_scaleFactor * m_physicalDpiY / 72.0 * m_size.height());
1021
981
        break;
1022
 
    case Poppler::Page::Rotate180:
1023
 
    case Poppler::Page::Rotate270:
 
982
    case RotateBy90:
 
983
    case RotateBy270:
1024
984
        m_transform.scale(m_scaleFactor * m_physicalDpiY / 72.0, m_scaleFactor * m_physicalDpiX / 72.0);
1025
985
        m_normalizedTransform.scale(m_scaleFactor * m_physicalDpiY / 72.0 * m_size.width(), m_scaleFactor * m_physicalDpiX / 72.0 * m_size.height());
1026
986
        break;
1032
992
    m_boundingRect.setHeight(qRound(m_boundingRect.height()));
1033
993
}
1034
994
 
1035
 
void PageItem::render(int physicalDpiX, int physicalDpiY, qreal scaleFactor, Poppler::Page::Rotation rotation, bool prefetch)
 
995
void PageItem::render(const RenderOptions& renderOptions)
1036
996
{
1037
 
    QMutexLocker mutexLocker(m_mutex);
1038
 
 
1039
 
    if(m_render->isCanceled() && !prefetch)
1040
 
    {
1041
 
        return;
1042
 
    }
1043
 
 
1044
 
    QImage image;
1045
 
 
1046
 
    switch(rotation)
1047
 
    {
1048
 
    case Poppler::Page::Rotate0:
1049
 
    case Poppler::Page::Rotate90:
1050
 
        image = m_page->renderToImage(scaleFactor * physicalDpiX, scaleFactor * physicalDpiY, -1, -1, -1, -1, rotation);
1051
 
        break;
1052
 
    case Poppler::Page::Rotate180:
1053
 
    case Poppler::Page::Rotate270:
1054
 
        image = m_page->renderToImage(scaleFactor * physicalDpiY, scaleFactor * physicalDpiX, -1, -1, -1, -1, rotation);
1055
 
        break;
1056
 
    }
1057
 
 
1058
 
    if(m_render->isCanceled() && !prefetch)
1059
 
    {
1060
 
        return;
1061
 
    }
1062
 
 
1063
 
    emit imageReady(physicalDpiX, physicalDpiY, scaleFactor, rotation, prefetch, image);
 
997
    if(m_render->isCanceled() && !renderOptions.prefetch)
 
998
    {
 
999
        return;
 
1000
    }
 
1001
 
 
1002
    QImage image = m_page->render(renderOptions.physicalDpiX * renderOptions.scaleFactor, renderOptions.physicalDpiY * renderOptions.scaleFactor, renderOptions.rotation);
 
1003
 
 
1004
    if(m_render->isCanceled() && !renderOptions.prefetch)
 
1005
    {
 
1006
        return;
 
1007
    }
 
1008
 
 
1009
    if(renderOptions.invertColors)
 
1010
    {
 
1011
        image.invertPixels();
 
1012
    }
 
1013
 
 
1014
    emit imageReady(renderOptions.physicalDpiX, renderOptions.physicalDpiY, renderOptions.scaleFactor, renderOptions.rotation, renderOptions.invertColors, renderOptions.prefetch, image);
1064
1015
}
1065
1016
 
1066
 
ThumbnailItem::ThumbnailItem(QMutex* mutex, Poppler::Page* page, int index, QGraphicsItem* parent) : PageItem(mutex, page, index, parent)
 
1017
ThumbnailItem::ThumbnailItem(Model::Page* page, int index, QGraphicsItem* parent) : PageItem(page, index, false, parent)
1067
1018
{
1068
1019
    setAcceptHoverEvents(false);
1069
1020
}
1073
1024
    emit linkClicked(index() + 1);
1074
1025
}
1075
1026
 
 
1027
void ThumbnailItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent*)
 
1028
{
 
1029
}
 
1030
 
1076
1031
void ThumbnailItem::mouseMoveEvent(QGraphicsSceneMouseEvent*)
1077
1032
{
1078
1033
}
1080
1035
void ThumbnailItem::mouseReleaseEvent(QGraphicsSceneMouseEvent*)
1081
1036
{
1082
1037
}
 
1038
 
 
1039
void ThumbnailItem::contextMenuEvent(QGraphicsSceneContextMenuEvent*)
 
1040
{
 
1041
}
 
1042
 
 
1043
void ThumbnailItem::loadInteractiveElements()
 
1044
{
 
1045
}