~adamreichold/qpdfview/trunk

« back to all changes in this revision

Viewing changes to sources/documentview.cpp

  • Committer: Adam Reichold
  • Date: 2012-07-01 17:37:17 UTC
  • Revision ID: adamreichold@myopera.com-20120701173717-rjw063ohuse3wcri
manual merge of future branch

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 
3
 
Copyright 2012 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 "documentview.h"
23
 
 
24
 
// static settings
25
 
 
26
 
const qreal DocumentView::pageSpacing = 5.0;
27
 
const qreal DocumentView::thumbnailSpacing = 2.5;
28
 
 
29
 
qreal DocumentView::thumbnailWidth = 96.0;
30
 
qreal DocumentView::thumbnailHeight = 144.0;
31
 
 
32
 
const qreal DocumentView::zoomBy = 0.1;
33
 
 
34
 
const qreal DocumentView::mininumScaleFactor = 0.1;
35
 
const qreal DocumentView::maximumScaleFactor = 5.0;
36
 
 
37
 
bool DocumentView::fitToEqualWidth = false;
38
 
 
39
 
bool DocumentView::highlightLinks = true;
40
 
bool DocumentView::externalLinks = false;
41
 
 
42
 
// page item
43
 
 
44
 
DocumentView::PageItem::PageItem(QGraphicsItem* parent, QGraphicsScene* scene) : QGraphicsItem(parent, scene),
45
 
    m_page(0),
46
 
    m_index(-1),
47
 
    m_scale(1.0),
48
 
    m_links(),
49
 
    m_rubberBand(),
50
 
    m_size(),
51
 
    m_linkTransform(),
52
 
    m_highlightTransform(),
53
 
    m_render()
54
 
{
55
 
    setAcceptHoverEvents(true);
56
 
}
57
 
 
58
 
DocumentView::PageItem::~PageItem()
59
 
{
60
 
    m_render.waitForFinished();
61
 
 
62
 
    if(m_page != 0)
63
 
    {
64
 
        delete m_page;
65
 
    }
66
 
}
67
 
 
68
 
QRectF DocumentView::PageItem::boundingRect() const
69
 
{
70
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
71
 
 
72
 
    return QRectF(0.0, 0.0, qCeil(m_scale * parent->m_resolutionX / 72.0 * m_size.width()), qCeil(m_scale * parent->m_resolutionY / 72.0 * m_size.height()));
73
 
}
74
 
 
75
 
void DocumentView::PageItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
76
 
{
77
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
78
 
 
79
 
    // page
80
 
 
81
 
    painter->fillRect(boundingRect(), QBrush(Qt::white));
82
 
 
83
 
#ifdef RENDER_IN_PAINT
84
 
 
85
 
    parent->m_documentMutex.lock();
86
 
 
87
 
    QImage image = m_page->renderToImage(m_scale * parent->m_resolutionX, m_scale * parent->m_resolutionY);
88
 
 
89
 
    parent->m_documentMutex.unlock();
90
 
 
91
 
    painter->drawImage(0.0, 0.0, image);
92
 
 
93
 
#else
94
 
 
95
 
    parent->m_pageCacheMutex.lock();
96
 
 
97
 
    DocumentView::PageCacheKey key(m_index, m_scale * parent->m_resolutionX, m_scale * parent->m_resolutionY);
98
 
 
99
 
    if(parent->m_pageCache.contains(key))
100
 
    {
101
 
        DocumentView::PageCacheValue& value = parent->m_pageCache[key];
102
 
 
103
 
        value.time = QTime::currentTime();
104
 
        painter->drawImage(0.0, 0.0, value.image);
105
 
    }
106
 
    else
107
 
    {
108
 
        if(!m_render.isRunning())
109
 
        {
110
 
            m_render = QtConcurrent::run(this, &DocumentView::PageItem::render, m_scale, false);
111
 
        }
112
 
    }
113
 
 
114
 
    parent->m_pageCacheMutex.unlock();
115
 
 
116
 
#endif
117
 
 
118
 
    painter->setPen(QPen(Qt::black));
119
 
    painter->drawRect(boundingRect());
120
 
 
121
 
    // links
122
 
 
123
 
    if(DocumentView::highlightLinks)
124
 
    {
125
 
        painter->save();
126
 
 
127
 
        painter->setTransform(m_linkTransform, true);
128
 
        painter->setPen(QPen(QColor(255, 0, 0, 127)));
129
 
 
130
 
        foreach(Link link, m_links)
131
 
        {
132
 
            painter->drawRect(link.area);
133
 
        }
134
 
 
135
 
        painter->restore();
136
 
    }
137
 
 
138
 
    // highlights
139
 
 
140
 
    painter->save();
141
 
 
142
 
    painter->setTransform(m_highlightTransform, true);
143
 
 
144
 
    if(parent->m_highlightAll)
145
 
    {
146
 
        foreach(QRectF highlight, parent->m_results.values(m_index))
147
 
        {
148
 
            painter->fillRect(highlight, QBrush(QColor(0, 255, 0, 127)));
149
 
        }
150
 
    }
151
 
 
152
 
    painter->restore();
153
 
 
154
 
    // rubber band
155
 
 
156
 
    if(!m_rubberBand.isNull())
157
 
    {
158
 
        painter->setPen(QPen(Qt::DashLine));
159
 
        painter->drawRect(m_rubberBand);
160
 
    }
161
 
}
162
 
 
163
 
void DocumentView::PageItem::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
164
 
{
165
 
    Q_UNUSED(event);
166
 
}
167
 
 
168
 
void DocumentView::PageItem::hoverMoveEvent(QGraphicsSceneHoverEvent* event)
169
 
{
170
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
171
 
 
172
 
    QApplication::restoreOverrideCursor();
173
 
 
174
 
    foreach(Link link, m_links)
175
 
    {
176
 
        if(m_linkTransform.mapRect(link.area).contains(event->pos()))
177
 
        {
178
 
            QApplication::setOverrideCursor(Qt::PointingHandCursor);
179
 
 
180
 
            if(link.page != -1)
181
 
            {
182
 
                QToolTip::showText(event->screenPos(), tr("Go to page %1.").arg(link.page), parent);
183
 
            }
184
 
            else if(!link.url.isEmpty())
185
 
            {
186
 
                QToolTip::showText(event->screenPos(), tr("Open URL \"%1\".").arg(link.url), parent);
187
 
            }
188
 
 
189
 
            return;
190
 
        }
191
 
    }
192
 
 
193
 
    QToolTip::hideText();
194
 
}
195
 
 
196
 
void DocumentView::PageItem::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
197
 
{
198
 
    Q_UNUSED(event);
199
 
}
200
 
 
201
 
void DocumentView::PageItem::mousePressEvent(QGraphicsSceneMouseEvent* event)
202
 
{
203
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
204
 
 
205
 
    if(event->button() == Qt::LeftButton)
206
 
    {
207
 
        foreach(Link link, m_links)
208
 
        {
209
 
            if(m_linkTransform.mapRect(link.area).contains(event->pos()))
210
 
            {
211
 
                if(link.page != -1)
212
 
                {
213
 
                    parent->setCurrentPage(link.page, link.top);
214
 
                }
215
 
                else if(!link.url.isEmpty())
216
 
                {
217
 
                    if(DocumentView::externalLinks)
218
 
                    {
219
 
                        QDesktopServices::openUrl(QUrl(link.url));
220
 
                    }
221
 
                    else
222
 
                    {
223
 
                        QMessageBox::information(parent, tr("Information"), tr("External links are disabled in the settings."));
224
 
                    }
225
 
                }
226
 
 
227
 
                event->accept();
228
 
 
229
 
                return;
230
 
            }
231
 
        }
232
 
 
233
 
        if(event->modifiers() == Qt::ShiftModifier)
234
 
        {
235
 
            m_rubberBand = QRectF(event->pos(), QSizeF());
236
 
 
237
 
            event->accept();
238
 
        }
239
 
        else
240
 
        {
241
 
            event->ignore();
242
 
        }
243
 
    }
244
 
    else
245
 
    {
246
 
        event->ignore();
247
 
    }
248
 
}
249
 
 
250
 
void DocumentView::PageItem::mouseMoveEvent(QGraphicsSceneMouseEvent* event)
251
 
{
252
 
    if(!m_rubberBand.isNull())
253
 
    {
254
 
        m_rubberBand.setBottomRight(event->pos());
255
 
 
256
 
        update(boundingRect());
257
 
 
258
 
        event->accept();
259
 
    }
260
 
    else
261
 
    {
262
 
        event->ignore();
263
 
    }
264
 
}
265
 
 
266
 
void DocumentView::PageItem::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
267
 
{
268
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
269
 
 
270
 
    if(!m_rubberBand.isNull())
271
 
    {
272
 
        m_rubberBand.setBottomRight(event->pos());
273
 
 
274
 
        m_rubberBand = m_rubberBand.normalized();
275
 
 
276
 
        // copy text or image
277
 
 
278
 
        QMenu menu(parent);
279
 
 
280
 
        QAction* copyTextAction = menu.addAction(tr("Copy &text"));
281
 
        QAction* copyImageAction = menu.addAction(tr("Copy &image"));
282
 
 
283
 
        QAction* action = menu.exec(event->screenPos());
284
 
 
285
 
        if(action == copyTextAction)
286
 
        {
287
 
            parent->m_documentMutex.lock();
288
 
 
289
 
            QString text = m_page->text(m_highlightTransform.inverted().mapRect(m_rubberBand));
290
 
 
291
 
            parent->m_documentMutex.unlock();
292
 
 
293
 
            if(!text.isEmpty())
294
 
            {
295
 
                QApplication::clipboard()->setText(text);
296
 
            }
297
 
        }
298
 
        else if(action == copyImageAction)
299
 
        {
300
 
            parent->m_documentMutex.lock();
301
 
 
302
 
            QImage image = m_page->renderToImage(m_scale * parent->m_resolutionX, m_scale * parent->m_resolutionY, m_rubberBand.x(), m_rubberBand.y(), m_rubberBand.width(), m_rubberBand.height());
303
 
 
304
 
            parent->m_documentMutex.unlock();
305
 
 
306
 
            if(!image.isNull())
307
 
            {
308
 
                QApplication::clipboard()->setImage(image);
309
 
            }
310
 
        }
311
 
 
312
 
        m_rubberBand = QRectF();
313
 
 
314
 
        update(boundingRect());
315
 
 
316
 
        event->accept();
317
 
    }
318
 
    else
319
 
    {
320
 
        event->ignore();
321
 
    }
322
 
}
323
 
 
324
 
void DocumentView::PageItem::render(qreal scale, bool prefetch)
325
 
{
326
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
327
 
 
328
 
    QRectF rect = parent->m_pageTransform.mapRect(boundingRect()).translated(pos());
329
 
    QRectF visibleRect = parent->m_view->mapToScene(parent->m_view->viewport()->rect()).boundingRect();
330
 
 
331
 
    if(!rect.intersects(visibleRect) && !prefetch)
332
 
    {
333
 
        return;
334
 
    }
335
 
 
336
 
#ifdef RENDER_FROM_DISK
337
 
 
338
 
    Poppler::Document* document = Poppler::Document::load(parent->m_filePath);
339
 
 
340
 
    if(document == 0)
341
 
    {
342
 
        qFatal("!document");
343
 
        return;
344
 
    }
345
 
 
346
 
    Poppler::Page* page = document->page(m_index);
347
 
 
348
 
    if(page == 0)
349
 
    {
350
 
        qFatal("!page");
351
 
        return;
352
 
    }
353
 
 
354
 
    Poppler::Document::RenderHints renderHints = parent->m_document->renderHints();
355
 
 
356
 
    document->setRenderHint(Poppler::Document::Antialiasing, renderHints.testFlag(Poppler::Document::Antialiasing));
357
 
    document->setRenderHint(Poppler::Document::TextAntialiasing, renderHints.testFlag(Poppler::Document::TextAntialiasing));
358
 
    document->setRenderHint(Poppler::Document::TextHinting, renderHints.testFlag(Poppler::Document::TextHinting));
359
 
 
360
 
    QImage image = page->renderToImage(scale * parent->m_resolutionX, scale * parent->m_resolutionY);
361
 
 
362
 
    delete page;
363
 
    delete document;
364
 
 
365
 
#else
366
 
 
367
 
    parent->m_documentMutex.lock();
368
 
 
369
 
    QImage image = m_page->renderToImage(scale * parent->m_resolutionX, scale * parent->m_resolutionY);
370
 
 
371
 
    parent->m_documentMutex.unlock();
372
 
 
373
 
#endif
374
 
 
375
 
    DocumentView::PageCacheKey key(m_index, scale * parent->m_resolutionX, scale * parent->m_resolutionY);
376
 
    DocumentView::PageCacheValue value(image);
377
 
 
378
 
    parent->updatePageCache(key, value);
379
 
 
380
 
    emit parent->pageItemChanged(m_index);
381
 
}
382
 
 
383
 
// thumbnail item
384
 
 
385
 
DocumentView::ThumbnailItem::ThumbnailItem(QGraphicsItem* parent, QGraphicsScene* scene) : QGraphicsItem(parent, scene),
386
 
    m_page(0),
387
 
    m_index(-1),
388
 
    m_scale(1.0),
389
 
    m_size(),
390
 
    m_render()
391
 
{
392
 
}
393
 
 
394
 
DocumentView::ThumbnailItem::~ThumbnailItem()
395
 
{
396
 
    m_render.waitForFinished();
397
 
 
398
 
    if(m_page != 0)
399
 
    {
400
 
        delete m_page;
401
 
    }
402
 
}
403
 
 
404
 
QRectF DocumentView::ThumbnailItem::boundingRect() const
405
 
{
406
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
407
 
 
408
 
    return QRectF(0.0, 0.0, qCeil(m_scale * parent->physicalDpiX() / 72.0 * m_size.width()), qCeil(m_scale * parent->physicalDpiY() / 72.0 * m_size.height()));
409
 
}
410
 
 
411
 
void DocumentView::ThumbnailItem::paint(QPainter* painter, const QStyleOptionGraphicsItem*, QWidget*)
412
 
{
413
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
414
 
 
415
 
    // page
416
 
 
417
 
    painter->fillRect(boundingRect(), QBrush(Qt::white));
418
 
 
419
 
#ifdef RENDER_IN_PAINT
420
 
 
421
 
    parent->m_documentMutex.lock();
422
 
 
423
 
    QImage image = m_page->renderToImage(m_scale * parent->physicalDpiX(), m_scale * parent->physicalDpiY());
424
 
 
425
 
    parent->m_documentMutex.unlock();
426
 
 
427
 
    painter->drawImage(0.0, 0.0, image);
428
 
 
429
 
#else
430
 
 
431
 
    parent->m_pageCacheMutex.lock();
432
 
 
433
 
    DocumentView::PageCacheKey key(m_index, m_scale * parent->physicalDpiX(), m_scale * parent->physicalDpiY());
434
 
 
435
 
    if(parent->m_pageCache.contains(key))
436
 
    {
437
 
        DocumentView::PageCacheValue& value = parent->m_pageCache[key];
438
 
 
439
 
        value.time = QTime::currentTime();
440
 
        painter->drawImage(0.0, 0.0, value.image);
441
 
    }
442
 
    else
443
 
    {
444
 
        if(!m_render.isRunning())
445
 
        {
446
 
            m_render = QtConcurrent::run(this, &DocumentView::ThumbnailItem::render, m_scale);
447
 
        }
448
 
    }
449
 
 
450
 
    parent->m_pageCacheMutex.unlock();
451
 
 
452
 
#endif
453
 
 
454
 
    painter->setPen(QPen(Qt::black));
455
 
    painter->drawRect(boundingRect());
456
 
}
457
 
 
458
 
void DocumentView::ThumbnailItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent*)
459
 
{
460
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
461
 
 
462
 
    parent->setCurrentPage(m_index + 1);
463
 
}
464
 
 
465
 
void DocumentView::ThumbnailItem::render(qreal scale)
466
 
{
467
 
    DocumentView* parent = qobject_cast< DocumentView* >(scene()->parent()); Q_ASSERT(parent);
468
 
 
469
 
    QRectF rect = boundingRect().translated(pos());
470
 
    QRectF visibleRect = parent->m_thumbnailsGraphicsView->mapToScene(parent->m_thumbnailsGraphicsView->viewport()->rect()).boundingRect();
471
 
 
472
 
    if(!rect.intersects(visibleRect))
473
 
    {
474
 
        return;
475
 
    }
476
 
 
477
 
#ifdef RENDER_FROM_DISK
478
 
 
479
 
    Poppler::Document* document = Poppler::Document::load(parent->m_filePath);
480
 
 
481
 
    if(document == 0)
482
 
    {
483
 
        qFatal("!document");
484
 
        return;
485
 
    }
486
 
 
487
 
    Poppler::Page* page = document->page(m_index);
488
 
 
489
 
    if(page == 0)
490
 
    {
491
 
        qFatal("!page");
492
 
        return;
493
 
    }
494
 
 
495
 
    Poppler::Document::RenderHints renderHints = parent->m_document->renderHints();
496
 
 
497
 
    document->setRenderHint(Poppler::Document::Antialiasing, renderHints.testFlag(Poppler::Document::Antialiasing));
498
 
    document->setRenderHint(Poppler::Document::TextAntialiasing, renderHints.testFlag(Poppler::Document::TextAntialiasing));
499
 
    document->setRenderHint(Poppler::Document::TextHinting, renderHints.testFlag(Poppler::Document::TextHinting));
500
 
 
501
 
    QImage image = page->renderToImage(scale * parent->physicalDpiX(), scale * parent->physicalDpiY());
502
 
 
503
 
    delete page;
504
 
    delete document;
505
 
 
506
 
#else
507
 
 
508
 
    parent->m_documentMutex.lock();
509
 
 
510
 
    QImage image = m_page->renderToImage(scale * parent->physicalDpiX(), scale * parent->physicalDpiY());
511
 
 
512
 
    parent->m_documentMutex.unlock();
513
 
 
514
 
#endif
515
 
 
516
 
    DocumentView::PageCacheKey key(m_index, scale * parent->physicalDpiX(), scale * parent->physicalDpiY());
517
 
    DocumentView::PageCacheValue value(image);
518
 
 
519
 
    parent->updatePageCache(key, value);
520
 
 
521
 
    emit parent->thumbnailItemChanged(m_index);
522
 
}
523
 
 
524
 
// document view
525
 
 
526
 
DocumentView::DocumentView(QWidget* parent) : QWidget(parent),
527
 
    m_document(0),
528
 
    m_documentMutex(),
529
 
    m_pageCache(),
530
 
    m_pageCacheMutex(),
531
 
    m_pageCacheSize(0u),
532
 
    m_maximumPageCacheSize(33554432u),
533
 
    m_filePath(),
534
 
    m_numberOfPages(-1),
535
 
    m_currentPage(-1),
536
 
    m_pageLayout(OnePage),
537
 
    m_scaleMode(DoNotScale),
538
 
    m_scaleFactor(1.0),
539
 
    m_rotation(RotateBy0),
540
 
    m_highlightAll(false),
541
 
    m_pagesByIndex(),
542
 
    m_pagesByHeight(),
543
 
    m_thumbnailsByIndex(),
544
 
    m_resolutionX(72.0),
545
 
    m_resolutionY(72.0),
546
 
    m_pageTransform(),
547
 
    m_autoRefreshWatcher(0),
548
 
    m_results(),
549
 
    m_resultsMutex(),
550
 
    m_currentResult(m_results.end()),
551
 
    m_search(),
552
 
    m_print()
553
 
{
554
 
    connect(this, SIGNAL(pageItemChanged(int)), SLOT(slotUpdatePageItem(int)));
555
 
    connect(this, SIGNAL(thumbnailItemChanged(int)), SLOT(slotUpdateThumbnailItem(int)));
556
 
 
557
 
    connect(this, SIGNAL(currentPageChanged(int)), SLOT(slotThumbnailsEnsureVisible(int)));
558
 
 
559
 
    connect(this, SIGNAL(firstResultFound()), SLOT(findNext()));
560
 
 
561
 
    // settings
562
 
 
563
 
    m_pageLayout = static_cast< PageLayout >(m_settings.value("documentView/pageLayout", static_cast< uint >(m_pageLayout)).toUInt());
564
 
    m_scaleMode = static_cast< ScaleMode >(m_settings.value("documentView/scaleMode", static_cast< uint >(m_scaleMode)).toUInt());
565
 
    m_scaleFactor = m_settings.value("documentView/scaleFactor", m_scaleFactor).toReal();
566
 
    m_rotation = static_cast< Rotation >(m_settings.value("documentView/rotation", static_cast< uint >(m_rotation)).toUInt());
567
 
 
568
 
    m_highlightAll = m_settings.value("documentView/highlightAll", m_highlightAll).toBool();
569
 
 
570
 
    // graphics
571
 
 
572
 
    m_scene = new QGraphicsScene(this);
573
 
    m_scene->setBackgroundBrush(QBrush(Qt::darkGray));
574
 
 
575
 
    m_view = new QGraphicsView(m_scene, this);
576
 
    m_view->setDragMode(QGraphicsView::ScrollHandDrag);
577
 
 
578
 
    m_view->setAcceptDrops(false);
579
 
 
580
 
    setFocusProxy(m_view);
581
 
 
582
 
    // highlight
583
 
 
584
 
    m_highlight = new QGraphicsRectItem();
585
 
    m_highlight->setPen(QPen(QColor(0, 255, 0, 255)));
586
 
    m_highlight->setBrush(QBrush(QColor(0, 255, 0, 127)));
587
 
    m_highlight->setVisible(false);
588
 
 
589
 
    m_scene->addItem(m_highlight);
590
 
 
591
 
    // vertical scrollbar
592
 
 
593
 
    m_view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
594
 
 
595
 
    connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(slotVerticalScrollBarValueChanged(int)));
596
 
 
597
 
    m_view->installEventFilter(this);
598
 
    m_view->verticalScrollBar()->installEventFilter(this);
599
 
 
600
 
    // auto-refresh timer
601
 
 
602
 
    m_autoRefreshTimer = new QTimer(this);
603
 
    m_autoRefreshTimer->setInterval(500);
604
 
    m_autoRefreshTimer->setSingleShot(true);
605
 
 
606
 
    connect(m_autoRefreshTimer, SIGNAL(timeout()), SLOT(refresh()));
607
 
 
608
 
    // prefetch timer
609
 
 
610
 
    m_prefetchTimer = new QTimer(this);
611
 
    m_prefetchTimer->setInterval(500);
612
 
    m_prefetchTimer->setSingleShot(true);
613
 
 
614
 
    connect(this, SIGNAL(currentPageChanged(int)), m_prefetchTimer, SLOT(start()));
615
 
    connect(this, SIGNAL(pageLayoutChanged(DocumentView::PageLayout)), m_prefetchTimer, SLOT(start()));
616
 
    connect(this, SIGNAL(scaleModeChanged(DocumentView::ScaleMode)), m_prefetchTimer, SLOT(start()));
617
 
 
618
 
    connect(m_prefetchTimer, SIGNAL(timeout()), SLOT(slotPrefetchTimerTimeout()));
619
 
 
620
 
    // bookmarks menu
621
 
 
622
 
    m_bookmarksMenu = new BookmarksMenu(this);
623
 
    m_bookmarksMenu->updateCurrentPage(m_currentPage);
624
 
    m_bookmarksMenu->updateValue(m_view->verticalScrollBar()->value());
625
 
    m_bookmarksMenu->updateRange(m_view->verticalScrollBar()->minimum(), m_view->verticalScrollBar()->maximum());
626
 
 
627
 
    connect(this, SIGNAL(currentPageChanged(int)), m_bookmarksMenu, SLOT(updateCurrentPage(int)));
628
 
    connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), m_bookmarksMenu, SLOT(updateValue(int)));
629
 
    connect(m_view->verticalScrollBar(), SIGNAL(rangeChanged(int,int)), m_bookmarksMenu, SLOT(updateRange(int,int)));
630
 
 
631
 
    connect(m_bookmarksMenu, SIGNAL(entrySelected(int,int)), SLOT(slotBookmarksMenuEntrySelected(int,int)));
632
 
 
633
 
    // tab action
634
 
 
635
 
    m_tabAction = new QAction(this);
636
 
 
637
 
    connect(m_tabAction, SIGNAL(triggered()), SLOT(slotTabActionTriggered()));
638
 
 
639
 
    // outline
640
 
 
641
 
    m_outlineTreeWidget = new QTreeWidget();
642
 
    m_outlineTreeWidget->setAlternatingRowColors(true);
643
 
    m_outlineTreeWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
644
 
    m_outlineTreeWidget->header()->setVisible(false);
645
 
    m_outlineTreeWidget->header()->setResizeMode(QHeaderView::Stretch);
646
 
 
647
 
    connect(m_outlineTreeWidget, SIGNAL(itemClicked(QTreeWidgetItem*,int)), SLOT(slotOutlineTreeWidgetItemClicked(QTreeWidgetItem*,int)));
648
 
 
649
 
    // meta-information
650
 
 
651
 
    m_metaInformationTableWidget = new QTableWidget();
652
 
    m_metaInformationTableWidget->setAlternatingRowColors(true);
653
 
    m_metaInformationTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
654
 
    m_metaInformationTableWidget->horizontalHeader()->setVisible(false);
655
 
    m_metaInformationTableWidget->horizontalHeader()->setResizeMode(QHeaderView::Stretch);
656
 
    m_metaInformationTableWidget->verticalHeader()->setVisible(false);
657
 
    m_metaInformationTableWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
658
 
 
659
 
    // thumbnails
660
 
 
661
 
    m_thumbnailsGraphicsView = new QGraphicsView(new QGraphicsScene(this));
662
 
    m_thumbnailsGraphicsView->scene()->setBackgroundBrush(QBrush(Qt::darkGray));
663
 
    m_thumbnailsGraphicsView->setDragMode(QGraphicsView::ScrollHandDrag);
664
 
}
665
 
 
666
 
DocumentView::~DocumentView()
667
 
{
668
 
    clearScene();
669
 
 
670
 
    m_search.cancel();
671
 
    m_search.waitForFinished();
672
 
 
673
 
    m_print.cancel();
674
 
    m_print.waitForFinished();
675
 
 
676
 
    if(m_document != 0)
677
 
    {
678
 
        delete m_document;
679
 
    }
680
 
 
681
 
    if(m_autoRefreshWatcher != 0)
682
 
    {
683
 
        delete m_autoRefreshWatcher;
684
 
    }
685
 
 
686
 
    delete m_outlineTreeWidget;
687
 
    delete m_metaInformationTableWidget;
688
 
    delete m_thumbnailsGraphicsView;
689
 
}
690
 
 
691
 
const QString& DocumentView::filePath() const
692
 
{
693
 
    return m_filePath;
694
 
}
695
 
 
696
 
int DocumentView::numberOfPages() const
697
 
{
698
 
    return m_numberOfPages;
699
 
}
700
 
 
701
 
int DocumentView::currentPage() const
702
 
{
703
 
    return m_currentPage;
704
 
}
705
 
 
706
 
DocumentView::PageLayout DocumentView::pageLayout() const
707
 
{
708
 
    return m_pageLayout;
709
 
}
710
 
 
711
 
void DocumentView::setPageLayout(DocumentView::PageLayout pageLayout)
712
 
{
713
 
    if(m_pageLayout != pageLayout)
714
 
    {
715
 
        m_pageLayout = pageLayout;
716
 
 
717
 
        m_settings.setValue("documentView/pageLayout", static_cast< uint >(m_pageLayout));
718
 
 
719
 
        if((m_pageLayout == TwoPages || m_pageLayout == TwoColumns) && m_currentPage % 2 == 0)
720
 
        {
721
 
            m_currentPage -= 1;
722
 
 
723
 
            emit currentPageChanged(m_currentPage);
724
 
        }
725
 
 
726
 
        prepareScene();
727
 
        prepareView();
728
 
 
729
 
        emit pageLayoutChanged(m_pageLayout);
730
 
    }
731
 
}
732
 
 
733
 
DocumentView::ScaleMode DocumentView::scaleMode() const
734
 
{
735
 
    return m_scaleMode;
736
 
}
737
 
 
738
 
void DocumentView::setScaleMode(DocumentView::ScaleMode scaleMode)
739
 
{
740
 
    if(m_scaleMode != scaleMode)
741
 
    {
742
 
        m_scaleMode = scaleMode;
743
 
 
744
 
        m_settings.setValue("documentView/scaleMode", static_cast< uint >(m_scaleMode));
745
 
 
746
 
        prepareScene();
747
 
        prepareView();
748
 
 
749
 
        emit scaleModeChanged(m_scaleMode);
750
 
    }
751
 
}
752
 
 
753
 
qreal DocumentView::scaleFactor() const
754
 
{
755
 
    return m_scaleFactor;
756
 
}
757
 
 
758
 
void DocumentView::setScaleFactor(qreal scaleFactor)
759
 
{
760
 
    if(m_scaleFactor != scaleFactor && scaleFactor >= mininumScaleFactor && scaleFactor <= maximumScaleFactor)
761
 
    {
762
 
        m_scaleFactor = scaleFactor;
763
 
 
764
 
        m_settings.setValue("documentView/scaleFactor", m_scaleFactor);
765
 
 
766
 
        prepareScene();
767
 
        prepareView();
768
 
 
769
 
        emit scaleFactorChanged(m_scaleFactor);
770
 
    }
771
 
}
772
 
 
773
 
DocumentView::Rotation DocumentView::rotation() const
774
 
{
775
 
    return m_rotation;
776
 
}
777
 
 
778
 
void DocumentView::setRotation(DocumentView::Rotation rotation)
779
 
{
780
 
    if(m_rotation != rotation)
781
 
    {
782
 
        m_rotation = rotation;
783
 
 
784
 
        m_settings.setValue("documentView/rotation", static_cast< uint >(m_rotation));
785
 
 
786
 
        prepareScene();
787
 
        prepareView();
788
 
 
789
 
        emit rotationChanged(m_rotation);
790
 
    }
791
 
}
792
 
 
793
 
bool DocumentView::highlightAll() const
794
 
{
795
 
    return m_highlightAll;
796
 
}
797
 
 
798
 
void DocumentView::setHighlightAll(bool highlightAll)
799
 
{
800
 
    if(m_highlightAll != highlightAll)
801
 
    {
802
 
        m_highlightAll = highlightAll;
803
 
 
804
 
        m_settings.setValue("documentView/highlightAll", m_highlightAll);
805
 
 
806
 
        foreach(PageItem* pageItem, m_pagesByIndex)
807
 
        {
808
 
            pageItem->update(pageItem->boundingRect());
809
 
        }
810
 
 
811
 
        emit highlightAllChanged(m_highlightAll);
812
 
    }
813
 
}
814
 
 
815
 
QAction* DocumentView::tabAction() const
816
 
{
817
 
    return m_tabAction;
818
 
}
819
 
 
820
 
QTreeWidget* DocumentView::outlineTreeWidget() const
821
 
{
822
 
    return m_outlineTreeWidget;
823
 
}
824
 
 
825
 
QTableWidget* DocumentView::metaInformationTableWidget() const
826
 
{
827
 
    return m_metaInformationTableWidget;
828
 
}
829
 
 
830
 
QGraphicsView* DocumentView::thumbnailsGraphicsView() const
831
 
{
832
 
    return m_thumbnailsGraphicsView;
833
 
}
834
 
 
835
 
QTableWidget* DocumentView::fontsTableWidget()
836
 
{
837
 
    QTableWidget* fontsTableWidget = new QTableWidget();
838
 
 
839
 
    fontsTableWidget->setAlternatingRowColors(true);
840
 
    fontsTableWidget->setSortingEnabled(true);
841
 
    fontsTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
842
 
    fontsTableWidget->horizontalHeader()->setResizeMode(QHeaderView::ResizeToContents);
843
 
    fontsTableWidget->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
844
 
    fontsTableWidget->verticalHeader()->setResizeMode(QHeaderView::ResizeToContents);
845
 
    fontsTableWidget->verticalHeader()->setVisible(false);
846
 
 
847
 
    m_documentMutex.lock();
848
 
 
849
 
    QList< Poppler::FontInfo > fonts = m_document->fonts();
850
 
 
851
 
    m_documentMutex.unlock();
852
 
 
853
 
    fontsTableWidget->setRowCount(fonts.count());
854
 
    fontsTableWidget->setColumnCount(5);
855
 
 
856
 
    fontsTableWidget->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Type") << tr("Embedded") << tr("Subset") << tr("File"));
857
 
 
858
 
    for(int index = 0; index < fonts.count(); index++)
859
 
    {
860
 
        Poppler::FontInfo font = fonts.at(index);
861
 
 
862
 
        fontsTableWidget->setItem(index, 0,new QTableWidgetItem(font.name()));
863
 
        fontsTableWidget->setItem(index, 1, new QTableWidgetItem(font.typeName()));
864
 
        fontsTableWidget->setItem(index, 2, new QTableWidgetItem(font.isEmbedded() ? tr("Yes") : tr("No")));
865
 
        fontsTableWidget->setItem(index, 3, new QTableWidgetItem(font.isSubset() ? tr("Yes") : tr("No")));
866
 
        fontsTableWidget->setItem(index, 4, new QTableWidgetItem(font.file()));
867
 
    }
868
 
 
869
 
    return fontsTableWidget;
870
 
}
871
 
 
872
 
void DocumentView::clearBookmarks()
873
 
{
874
 
    m_bookmarksMenu->clearList();
875
 
}
876
 
 
877
 
bool DocumentView::open(const QString& filePath)
878
 
{
879
 
    m_prefetchTimer->blockSignals(true);
880
 
 
881
 
    Poppler::Document* document = Poppler::Document::load(filePath);
882
 
 
883
 
    if(document != 0)
884
 
    {
885
 
        if(document->isLocked())
886
 
        {
887
 
            QString password = QInputDialog::getText(0, tr("Password"), tr("Please enter the password required to unlock the document file \"%1\".").arg(filePath), QLineEdit::Password);
888
 
 
889
 
            if(document->unlock(password.toLatin1(), password.toLatin1()))
890
 
            {
891
 
                qWarning() << tr("Could not unlock the document file \"%1\".").arg(filePath);
892
 
 
893
 
                delete document;
894
 
                return false;
895
 
            }
896
 
        }
897
 
 
898
 
        clearScene();
899
 
 
900
 
        cancelSearch();
901
 
        cancelPrint();
902
 
 
903
 
        if(m_document != 0)
904
 
        {
905
 
            delete m_document;
906
 
        }
907
 
 
908
 
        if(m_autoRefreshWatcher != 0)
909
 
        {
910
 
            delete m_autoRefreshWatcher;
911
 
        }
912
 
 
913
 
        m_document = document;
914
 
 
915
 
        if(m_settings.value("documentView/autoRefresh", false).toBool())
916
 
        {
917
 
            m_autoRefreshWatcher = new QFileSystemWatcher(QStringList(filePath));
918
 
 
919
 
            connect(m_autoRefreshWatcher, SIGNAL(fileChanged(QString)), m_autoRefreshTimer, SLOT(start()));
920
 
        }
921
 
 
922
 
        m_filePath = filePath;
923
 
        m_numberOfPages = m_document->numPages();
924
 
 
925
 
        emit filePathChanged(m_filePath);
926
 
        emit numberOfPagesChanged(m_numberOfPages);
927
 
 
928
 
        m_currentPage = 1;
929
 
 
930
 
        emit currentPageChanged(m_currentPage);
931
 
 
932
 
        QFileInfo fileInfo(m_filePath);
933
 
 
934
 
        m_tabAction->setText(fileInfo.completeBaseName());
935
 
        m_tabAction->setToolTip(fileInfo.absoluteFilePath());
936
 
 
937
 
        preparePages();
938
 
 
939
 
        prepareOutline();
940
 
        prepareMetaInformation();
941
 
        prepareThumbnails();
942
 
 
943
 
        m_document->setRenderHint(Poppler::Document::Antialiasing, m_settings.value("documentView/antialiasing", true).toBool());
944
 
        m_document->setRenderHint(Poppler::Document::TextAntialiasing, m_settings.value("documentView/textAntialiasing", true).toBool());
945
 
        m_document->setRenderHint(Poppler::Document::TextHinting, m_settings.value("documentView/textHinting", false).toBool());
946
 
 
947
 
        clearPageCache();
948
 
 
949
 
        prepareScene();
950
 
        prepareView();
951
 
 
952
 
        if(m_settings.value("documentView/prefetch").toBool())
953
 
        {
954
 
            m_prefetchTimer->blockSignals(false);
955
 
            m_prefetchTimer->start();
956
 
        }
957
 
    }
958
 
 
959
 
    return document != 0;
960
 
}
961
 
 
962
 
bool DocumentView::refresh()
963
 
{
964
 
    m_prefetchTimer->blockSignals(true);
965
 
 
966
 
    Poppler::Document* document = Poppler::Document::load(m_filePath);
967
 
 
968
 
    if(document != 0)
969
 
    {
970
 
        if(document->isLocked())
971
 
        {
972
 
            QString password = QInputDialog::getText(0, tr("Password"), tr("Please enter the password required to unlock the document file \"%1\".").arg(m_filePath), QLineEdit::Password);
973
 
 
974
 
            if(document->unlock(password.toLatin1(), password.toLatin1()))
975
 
            {
976
 
                qWarning() << tr("Could not unlock the document file \"%1\".").arg(m_filePath);
977
 
 
978
 
                delete document;
979
 
                return false;
980
 
            }
981
 
        }
982
 
 
983
 
        clearScene();
984
 
 
985
 
        cancelSearch();
986
 
        cancelPrint();
987
 
 
988
 
        if(m_document != 0)
989
 
        {
990
 
            delete m_document;
991
 
        }
992
 
 
993
 
        m_document = document;
994
 
 
995
 
        int numberOfPages = m_document->numPages();
996
 
 
997
 
        if(m_numberOfPages != numberOfPages)
998
 
        {
999
 
            m_numberOfPages = numberOfPages;
1000
 
 
1001
 
            emit numberOfPagesChanged(m_numberOfPages);
1002
 
        }
1003
 
 
1004
 
        if(m_currentPage > m_numberOfPages)
1005
 
        {
1006
 
            m_currentPage = 1;
1007
 
 
1008
 
            emit currentPageChanged(m_currentPage);
1009
 
        }
1010
 
 
1011
 
        preparePages();
1012
 
 
1013
 
        prepareOutline();
1014
 
        prepareMetaInformation();
1015
 
        prepareThumbnails();
1016
 
 
1017
 
        m_document->setRenderHint(Poppler::Document::Antialiasing, m_settings.value("documentView/antialiasing", true).toBool());
1018
 
        m_document->setRenderHint(Poppler::Document::TextAntialiasing, m_settings.value("documentView/textAntialiasing", true).toBool());
1019
 
        m_document->setRenderHint(Poppler::Document::TextHinting, m_settings.value("documentView/textHinting", false).toBool());
1020
 
 
1021
 
        clearPageCache();
1022
 
 
1023
 
        prepareScene();
1024
 
        prepareView();
1025
 
 
1026
 
        if(m_settings.value("documentView/prefetch").toBool())
1027
 
        {
1028
 
            m_prefetchTimer->blockSignals(false);
1029
 
            m_prefetchTimer->start();
1030
 
        }
1031
 
    }
1032
 
 
1033
 
    return document != 0;
1034
 
}
1035
 
 
1036
 
bool DocumentView::saveCopy(const QString& filePath)
1037
 
{
1038
 
    if(m_document != 0)
1039
 
    {
1040
 
        m_documentMutex.lock();
1041
 
 
1042
 
        Poppler::PDFConverter* converter = m_document->pdfConverter();
1043
 
 
1044
 
        converter->setOutputFileName(filePath);
1045
 
 
1046
 
        bool success = converter->convert();
1047
 
 
1048
 
        delete converter;
1049
 
 
1050
 
        m_documentMutex.unlock();
1051
 
 
1052
 
        return success;
1053
 
    }
1054
 
 
1055
 
    return false;
1056
 
}
1057
 
 
1058
 
void DocumentView::setCurrentPage(int currentPage, qreal top)
1059
 
{
1060
 
    if(currentPage >= 1 && currentPage <= m_numberOfPages && top >= 0.0 && top <= 1.0)
1061
 
    {
1062
 
        PageItem* pageItem = m_pagesByIndex.value(m_currentPage - 1, 0);
1063
 
 
1064
 
        if(pageItem != 0)
1065
 
        {
1066
 
            QRectF rect = m_pageTransform.mapRect(pageItem->boundingRect()).translated(pageItem->pos());
1067
 
 
1068
 
            switch(m_pageLayout)
1069
 
            {
1070
 
            case OnePage:
1071
 
            case OneColumn:
1072
 
                if(m_currentPage != currentPage)
1073
 
                {
1074
 
                    m_bookmarksMenu->setReturnPosition(m_currentPage, m_view->verticalScrollBar()->value());
1075
 
 
1076
 
                    m_currentPage = currentPage;
1077
 
 
1078
 
                    prepareView(top);
1079
 
 
1080
 
                    emit currentPageChanged(m_currentPage);
1081
 
                }
1082
 
                else if(!qFuzzyCompare(1.0 + (qCeil(m_view->verticalScrollBar()->value() - rect.top()) / rect.height()), 1.0 + top))
1083
 
                {
1084
 
                    prepareView(top);
1085
 
                }
1086
 
 
1087
 
                break;
1088
 
            case TwoPages:
1089
 
            case TwoColumns:
1090
 
                if(m_currentPage != (currentPage % 2 != 0 ? currentPage : currentPage - 1))
1091
 
                {
1092
 
                    m_bookmarksMenu->setReturnPosition(m_currentPage, m_view->verticalScrollBar()->value());
1093
 
 
1094
 
                    m_currentPage = currentPage % 2 != 0 ? currentPage : currentPage - 1;
1095
 
 
1096
 
                    prepareView(top);
1097
 
 
1098
 
                    emit currentPageChanged(m_currentPage);
1099
 
                }
1100
 
                else if(!qFuzzyCompare(1.0 + (qCeil(m_view->verticalScrollBar()->value() - rect.top()) / rect.height()), 1.0 + top))
1101
 
                {
1102
 
                    prepareView(top);
1103
 
                }
1104
 
 
1105
 
                break;
1106
 
            }
1107
 
        }
1108
 
    }
1109
 
}
1110
 
 
1111
 
void DocumentView::previousPage()
1112
 
{
1113
 
    switch(m_pageLayout)
1114
 
    {
1115
 
    case OnePage:
1116
 
    case OneColumn:
1117
 
        if(m_currentPage > 1)
1118
 
        {
1119
 
            m_currentPage -= 1;
1120
 
 
1121
 
            prepareView();
1122
 
 
1123
 
            emit currentPageChanged(m_currentPage);
1124
 
        }
1125
 
 
1126
 
        break;
1127
 
    case TwoPages:
1128
 
    case TwoColumns:
1129
 
        if(m_currentPage > 1)
1130
 
        {
1131
 
            m_currentPage -= 2;
1132
 
 
1133
 
            prepareView();
1134
 
 
1135
 
            emit currentPageChanged(m_currentPage);
1136
 
        }
1137
 
 
1138
 
        break;
1139
 
    }
1140
 
}
1141
 
 
1142
 
void DocumentView::nextPage()
1143
 
{
1144
 
    switch(m_pageLayout)
1145
 
    {
1146
 
    case OnePage:
1147
 
    case OneColumn:
1148
 
        if(m_currentPage < m_numberOfPages)
1149
 
        {
1150
 
            m_currentPage += 1;
1151
 
 
1152
 
            prepareView();
1153
 
 
1154
 
            emit currentPageChanged(m_currentPage);
1155
 
        }
1156
 
 
1157
 
        break;
1158
 
    case TwoPages:
1159
 
    case TwoColumns:
1160
 
        if(m_currentPage < (m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1))
1161
 
        {
1162
 
            m_currentPage += 2;
1163
 
 
1164
 
            prepareView();
1165
 
 
1166
 
            emit currentPageChanged(m_currentPage);
1167
 
        }
1168
 
 
1169
 
        break;
1170
 
    }
1171
 
}
1172
 
 
1173
 
void DocumentView::firstPage()
1174
 
{
1175
 
    if(m_currentPage != 1)
1176
 
    {
1177
 
        m_currentPage = 1;
1178
 
 
1179
 
        prepareView();
1180
 
 
1181
 
        emit currentPageChanged(m_currentPage);
1182
 
    }
1183
 
}
1184
 
 
1185
 
void DocumentView::lastPage()
1186
 
{
1187
 
    switch(m_pageLayout)
1188
 
    {
1189
 
    case OnePage:
1190
 
    case OneColumn:
1191
 
        if(m_currentPage != m_numberOfPages)
1192
 
        {
1193
 
            m_currentPage = m_numberOfPages;
1194
 
 
1195
 
            prepareView();
1196
 
 
1197
 
            emit currentPageChanged(m_currentPage);
1198
 
        }
1199
 
 
1200
 
        break;
1201
 
    case TwoPages:
1202
 
    case TwoColumns:
1203
 
        if(m_currentPage != (m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1))
1204
 
        {
1205
 
            m_currentPage = m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1;
1206
 
 
1207
 
            prepareView();
1208
 
 
1209
 
            emit currentPageChanged(m_currentPage);
1210
 
        }
1211
 
 
1212
 
        break;
1213
 
    }
1214
 
}
1215
 
 
1216
 
void DocumentView::zoomIn()
1217
 
{
1218
 
    PageItem* pageItem = m_pagesByIndex.value(m_currentPage - 1, 0);
1219
 
 
1220
 
    switch(m_scaleMode)
1221
 
    {
1222
 
    case FitToPage:
1223
 
    case FitToPageWidth:
1224
 
        if(pageItem != 0)
1225
 
        {
1226
 
            setScaleFactor(qMin(pageItem->m_scale + zoomBy, maximumScaleFactor));
1227
 
            setScaleMode(ScaleFactor);
1228
 
 
1229
 
            break;
1230
 
        }
1231
 
    case DoNotScale:
1232
 
        setScaleFactor(1.0 + zoomBy);
1233
 
        setScaleMode(ScaleFactor);
1234
 
 
1235
 
        break;
1236
 
    case ScaleFactor:
1237
 
        setScaleFactor(qMin(scaleFactor() + zoomBy, maximumScaleFactor));
1238
 
 
1239
 
        break;
1240
 
    }
1241
 
}
1242
 
 
1243
 
void DocumentView::zoomOut()
1244
 
{
1245
 
    PageItem* pageItem = m_pagesByIndex.value(m_currentPage - 1, 0);
1246
 
 
1247
 
    switch(m_scaleMode)
1248
 
    {
1249
 
    case FitToPage:
1250
 
    case FitToPageWidth:
1251
 
        if(pageItem != 0)
1252
 
        {
1253
 
            setScaleFactor(qMax(pageItem->m_scale - zoomBy, mininumScaleFactor));
1254
 
            setScaleMode(ScaleFactor);
1255
 
 
1256
 
            break;
1257
 
        }
1258
 
    case DoNotScale:
1259
 
        setScaleFactor(1.0 - zoomBy);
1260
 
        setScaleMode(ScaleFactor);
1261
 
 
1262
 
        break;
1263
 
    case ScaleFactor:
1264
 
        setScaleFactor(qMax(scaleFactor() - zoomBy, mininumScaleFactor));
1265
 
 
1266
 
        break;
1267
 
    }
1268
 
}
1269
 
 
1270
 
void DocumentView::rotateLeft()
1271
 
{
1272
 
    switch(m_rotation)
1273
 
    {
1274
 
    case RotateBy0:
1275
 
        setRotation(RotateBy270); break;
1276
 
    case RotateBy90:
1277
 
        setRotation(RotateBy0); break;
1278
 
    case RotateBy180:
1279
 
        setRotation(RotateBy90); break;
1280
 
    case RotateBy270:
1281
 
        setRotation(RotateBy180); break;
1282
 
    }
1283
 
}
1284
 
 
1285
 
void DocumentView::rotateRight()
1286
 
{
1287
 
    switch(m_rotation)
1288
 
    {
1289
 
    case RotateBy0:
1290
 
        setRotation(RotateBy90); break;
1291
 
    case RotateBy90:
1292
 
        setRotation(RotateBy180); break;
1293
 
    case RotateBy180:
1294
 
        setRotation(RotateBy270); break;
1295
 
    case RotateBy270:
1296
 
        setRotation(RotateBy0); break;
1297
 
    }
1298
 
}
1299
 
 
1300
 
void DocumentView::startSearch(const QString& text, bool matchCase)
1301
 
{
1302
 
    cancelSearch();
1303
 
 
1304
 
    if(m_document != 0 && !text.isEmpty())
1305
 
    {
1306
 
        m_search = QtConcurrent::run(this, &DocumentView::search, text, matchCase);
1307
 
    }
1308
 
}
1309
 
 
1310
 
void DocumentView::cancelSearch()
1311
 
{
1312
 
    m_search.cancel();
1313
 
    m_search.waitForFinished();
1314
 
 
1315
 
    m_resultsMutex.lock();
1316
 
 
1317
 
    m_results.clear();
1318
 
    m_currentResult = m_results.end();
1319
 
 
1320
 
    m_resultsMutex.unlock();
1321
 
 
1322
 
    m_highlight->setVisible(false);
1323
 
 
1324
 
    if(m_highlightAll)
1325
 
    {
1326
 
        foreach(PageItem* pageItem, m_pagesByIndex)
1327
 
        {
1328
 
            pageItem->update(pageItem->boundingRect());
1329
 
        }
1330
 
    }
1331
 
}
1332
 
 
1333
 
void DocumentView::findPrevious()
1334
 
{
1335
 
    if(m_currentResult != m_results.end())
1336
 
    {
1337
 
        switch(m_pageLayout)
1338
 
        {
1339
 
        case OnePage:
1340
 
        case OneColumn:
1341
 
            if(m_currentResult.key() != m_currentPage - 1)
1342
 
            {
1343
 
                m_currentResult = --m_results.upperBound(m_currentPage - 1);
1344
 
            }
1345
 
            else
1346
 
            {
1347
 
                --m_currentResult;
1348
 
            }
1349
 
 
1350
 
            if(m_currentResult == m_results.end())
1351
 
            {
1352
 
                m_currentResult = --m_results.upperBound(m_numberOfPages - 1);
1353
 
            }
1354
 
 
1355
 
            break;
1356
 
        case TwoPages:
1357
 
        case TwoColumns:
1358
 
            if(m_currentResult.key() != m_currentPage - 1 && m_currentResult.key() != m_currentPage)
1359
 
            {
1360
 
                m_currentResult = --m_results.upperBound(m_currentPage - 1);
1361
 
            }
1362
 
            else
1363
 
            {
1364
 
                --m_currentResult;
1365
 
            }
1366
 
 
1367
 
            if(m_currentResult == m_results.end())
1368
 
            {
1369
 
                m_currentResult = --m_results.upperBound(m_numberOfPages - 1);
1370
 
            }
1371
 
 
1372
 
            break;
1373
 
        }
1374
 
    }
1375
 
    else
1376
 
    {
1377
 
        m_currentResult = --m_results.upperBound(m_currentPage - 1);
1378
 
 
1379
 
        if(m_currentResult == m_results.end())
1380
 
        {
1381
 
            m_currentResult = --m_results.upperBound(m_numberOfPages - 1);
1382
 
        }
1383
 
    }
1384
 
 
1385
 
    if(m_currentResult != m_results.end())
1386
 
    {
1387
 
        switch(m_pageLayout)
1388
 
        {
1389
 
        case OnePage:
1390
 
        case OneColumn:
1391
 
            if(m_currentPage != m_currentResult.key() + 1)
1392
 
            {
1393
 
                m_currentPage = m_currentResult.key() + 1;
1394
 
 
1395
 
                emit currentPageChanged(m_currentPage);
1396
 
            }
1397
 
 
1398
 
            break;
1399
 
        case TwoPages:
1400
 
        case TwoColumns:
1401
 
            if(m_currentPage != (m_currentResult.key() % 2 == 0 ? m_currentResult.key() + 1 : m_currentResult.key()))
1402
 
            {
1403
 
                m_currentPage = m_currentResult.key() % 2 == 0 ? m_currentResult.key() + 1 : m_currentResult.key();
1404
 
 
1405
 
                emit currentPageChanged(m_currentPage);
1406
 
            }
1407
 
        }
1408
 
 
1409
 
        prepareView();
1410
 
 
1411
 
        disconnect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
1412
 
 
1413
 
        m_view->centerOn(m_highlight);
1414
 
 
1415
 
        connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
1416
 
    }
1417
 
}
1418
 
 
1419
 
void DocumentView::findNext()
1420
 
{
1421
 
    if(m_currentResult != m_results.end())
1422
 
    {
1423
 
        switch(m_pageLayout)
1424
 
        {
1425
 
        case OnePage:
1426
 
        case OneColumn:
1427
 
            if(m_currentResult.key() != m_currentPage - 1)
1428
 
            {
1429
 
                m_currentResult = --m_results.upperBound(m_currentPage - 1);
1430
 
            }
1431
 
            else
1432
 
            {
1433
 
                ++m_currentResult;
1434
 
            }
1435
 
 
1436
 
            if(m_currentResult == m_results.end())
1437
 
            {
1438
 
                m_currentResult = m_results.lowerBound(0);
1439
 
            }
1440
 
 
1441
 
            break;
1442
 
        case TwoPages:
1443
 
        case TwoColumns:
1444
 
            if(m_currentResult.key() != m_currentPage - 1 && m_currentResult.key() != m_currentPage)
1445
 
            {
1446
 
                m_currentResult = --m_results.upperBound(m_currentPage - 1);
1447
 
            }
1448
 
            else
1449
 
            {
1450
 
                ++m_currentResult;
1451
 
            }
1452
 
 
1453
 
            if(m_currentResult == m_results.end())
1454
 
            {
1455
 
                m_currentResult = m_results.lowerBound(0);
1456
 
            }
1457
 
 
1458
 
            break;
1459
 
        }
1460
 
    }
1461
 
    else
1462
 
    {
1463
 
        m_currentResult = m_results.lowerBound(m_currentPage - 1);
1464
 
 
1465
 
        if(m_currentResult == m_results.end())
1466
 
        {
1467
 
            m_currentResult = m_results.lowerBound(0);
1468
 
        }
1469
 
    }
1470
 
 
1471
 
    if(m_currentResult != m_results.end())
1472
 
    {
1473
 
        switch(m_pageLayout)
1474
 
        {
1475
 
        case OnePage:
1476
 
        case OneColumn:
1477
 
            if(m_currentPage != m_currentResult.key() + 1)
1478
 
            {
1479
 
                m_currentPage = m_currentResult.key() + 1;
1480
 
 
1481
 
                emit currentPageChanged(m_currentPage);
1482
 
            }
1483
 
 
1484
 
            break;
1485
 
        case TwoPages:
1486
 
        case TwoColumns:
1487
 
            if(m_currentPage != (m_currentResult.key() % 2 == 0 ? m_currentResult.key() + 1 : m_currentResult.key()))
1488
 
            {
1489
 
                m_currentPage = m_currentResult.key() % 2 == 0 ? m_currentResult.key() + 1 : m_currentResult.key();
1490
 
 
1491
 
                emit currentPageChanged(m_currentPage);
1492
 
            }
1493
 
        }
1494
 
 
1495
 
        prepareView();
1496
 
 
1497
 
        disconnect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
1498
 
 
1499
 
        m_view->centerOn(m_highlight);
1500
 
 
1501
 
        connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
1502
 
    }
1503
 
}
1504
 
 
1505
 
void DocumentView::startPrint(QPrinter* printer, int fromPage, int toPage)
1506
 
{
1507
 
    cancelPrint();
1508
 
 
1509
 
    if(m_document != 0 && fromPage >= 1 && fromPage <= m_numberOfPages && toPage >= 1 && toPage <= m_numberOfPages && fromPage <= toPage)
1510
 
    {
1511
 
        m_print = QtConcurrent::run(this, &DocumentView::print, printer, fromPage, toPage);
1512
 
    }
1513
 
}
1514
 
 
1515
 
void DocumentView::cancelPrint()
1516
 
{
1517
 
    m_print.cancel();
1518
 
    m_print.waitForFinished();
1519
 
}
1520
 
 
1521
 
bool DocumentView::eventFilter(QObject* object, QEvent* event)
1522
 
{
1523
 
    if(object == m_view && event->type() == QEvent::KeyPress)
1524
 
    {
1525
 
        QKeyEvent* keyEvent = static_cast< QKeyEvent* >(event);
1526
 
 
1527
 
        if(keyEvent->modifiers() == Qt::NoModifier && (keyEvent->key() == Qt::Key_PageUp || keyEvent->key() == Qt::Key_PageDown))
1528
 
        {
1529
 
            keyPressEvent(keyEvent);
1530
 
 
1531
 
            return true;
1532
 
        }
1533
 
    }
1534
 
    else if(object == m_view->verticalScrollBar() && event->type() == QEvent::Wheel)
1535
 
    {
1536
 
        QWheelEvent* wheelEvent = static_cast< QWheelEvent* >(event);
1537
 
 
1538
 
        return wheelEvent->modifiers() == Qt::ControlModifier || wheelEvent->modifiers() == Qt::ShiftModifier || wheelEvent->modifiers() == Qt::AltModifier;
1539
 
    }
1540
 
 
1541
 
    return false;
1542
 
}
1543
 
 
1544
 
void DocumentView::showEvent(QShowEvent* event)
1545
 
{
1546
 
    if(!event->spontaneous())
1547
 
    {
1548
 
        m_view->show();
1549
 
 
1550
 
        prepareScene();
1551
 
        prepareView();
1552
 
    }
1553
 
}
1554
 
 
1555
 
void DocumentView::resizeEvent(QResizeEvent* event)
1556
 
{
1557
 
    m_view->resize(event->size());
1558
 
 
1559
 
    if(m_scaleMode == FitToPage || m_scaleMode == FitToPageWidth)
1560
 
    {
1561
 
        prepareScene();
1562
 
        prepareView();
1563
 
    }
1564
 
}
1565
 
 
1566
 
void DocumentView::contextMenuEvent(QContextMenuEvent* event)
1567
 
{
1568
 
    m_bookmarksMenu->exec(event->globalPos());
1569
 
}
1570
 
 
1571
 
void DocumentView::keyPressEvent(QKeyEvent* event)
1572
 
{
1573
 
    if(event->modifiers() == Qt::NoModifier && (event->key() == Qt::Key_PageUp || event->key() == Qt::Key_Backspace))
1574
 
    {
1575
 
        switch(m_pageLayout)
1576
 
        {
1577
 
        case OnePage:
1578
 
        case TwoPages:
1579
 
            if(m_view->verticalScrollBar()->value() == m_view->verticalScrollBar()->minimum() && m_currentPage > 1)
1580
 
            {
1581
 
                previousPage();
1582
 
 
1583
 
                m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->maximum());
1584
 
            }
1585
 
            else if(m_view->verticalScrollBar()->value() - m_view->verticalScrollBar()->pageStep() < m_view->verticalScrollBar()->minimum())
1586
 
            {
1587
 
                m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->minimum());
1588
 
            }
1589
 
            else
1590
 
            {
1591
 
                m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->value() - m_view->verticalScrollBar()->pageStep());
1592
 
            }
1593
 
 
1594
 
            break;
1595
 
        case OneColumn:
1596
 
        case TwoColumns:
1597
 
            m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->value() - m_view->verticalScrollBar()->pageStep());
1598
 
 
1599
 
            break;
1600
 
        }
1601
 
    }
1602
 
    else if(event->modifiers() == Qt::NoModifier && (event->key() == Qt::Key_PageDown || event->key() == Qt::Key_Space))
1603
 
    {
1604
 
        int lastPage = -1;
1605
 
 
1606
 
        switch(m_pageLayout)
1607
 
        {
1608
 
            case OnePage:
1609
 
            case OneColumn:
1610
 
                lastPage = m_numberOfPages; break;
1611
 
            case TwoPages:
1612
 
            case TwoColumns:
1613
 
                lastPage = m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1; break;
1614
 
        }
1615
 
 
1616
 
        switch(m_pageLayout)
1617
 
        {
1618
 
        case OnePage:
1619
 
        case TwoPages:
1620
 
            if(m_view->verticalScrollBar()->value() == m_view->verticalScrollBar()->maximum() && m_currentPage < lastPage)
1621
 
            {
1622
 
                nextPage();
1623
 
 
1624
 
                m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->minimum());
1625
 
            }
1626
 
            else if(m_view->verticalScrollBar()->value() + m_view->verticalScrollBar()->pageStep() > m_view->verticalScrollBar()->maximum())
1627
 
            {
1628
 
                m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->maximum());
1629
 
            }
1630
 
            else
1631
 
            {
1632
 
                m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->value() + m_view->verticalScrollBar()->pageStep());
1633
 
            }
1634
 
 
1635
 
            break;
1636
 
        case OneColumn:
1637
 
        case TwoColumns:
1638
 
            m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->value() + m_view->verticalScrollBar()->pageStep());
1639
 
 
1640
 
            break;
1641
 
        }
1642
 
    }
1643
 
    else
1644
 
    {
1645
 
        QKeySequence shortcut(event->modifiers() + event->key());
1646
 
 
1647
 
        foreach(QAction* action, m_bookmarksMenu->actions())
1648
 
        {
1649
 
            if(action->shortcut() == shortcut)
1650
 
            {
1651
 
                action->trigger();
1652
 
 
1653
 
                return;
1654
 
            }
1655
 
        }
1656
 
    }
1657
 
}
1658
 
 
1659
 
void DocumentView::wheelEvent(QWheelEvent* event)
1660
 
{
1661
 
    if(event->modifiers() == Qt::NoModifier)
1662
 
    {
1663
 
        int lastPage = -1;
1664
 
 
1665
 
        switch(m_pageLayout)
1666
 
        {
1667
 
            case OnePage:
1668
 
            case OneColumn:
1669
 
                lastPage = m_numberOfPages; break;
1670
 
            case TwoPages:
1671
 
            case TwoColumns:
1672
 
                lastPage = m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1; break;
1673
 
        }
1674
 
 
1675
 
        switch(m_pageLayout)
1676
 
        {
1677
 
        case OnePage:
1678
 
        case TwoPages:
1679
 
            if(event->delta() > 0 && m_view->verticalScrollBar()->value() == m_view->verticalScrollBar()->minimum() && m_currentPage > 1)
1680
 
            {
1681
 
                previousPage();
1682
 
 
1683
 
                m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->maximum());
1684
 
            }
1685
 
            else if(event->delta() < 0 && m_view->verticalScrollBar()->value() == m_view->verticalScrollBar()->maximum() && m_currentPage < lastPage)
1686
 
            {
1687
 
                nextPage();
1688
 
 
1689
 
                m_view->verticalScrollBar()->setValue(m_view->verticalScrollBar()->minimum());
1690
 
            }
1691
 
 
1692
 
            break;
1693
 
        case OneColumn:
1694
 
        case TwoColumns:
1695
 
            break;
1696
 
        }
1697
 
    }
1698
 
    else if(event->modifiers() == Qt::ControlModifier)
1699
 
    {
1700
 
        if(event->delta() > 0)
1701
 
        {
1702
 
            zoomIn();
1703
 
        }
1704
 
        else if(event->delta() < 0)
1705
 
        {
1706
 
            zoomOut();
1707
 
        }
1708
 
    }
1709
 
    else if(event->modifiers() == Qt::ShiftModifier)
1710
 
    {
1711
 
        if(event->delta() > 0)
1712
 
        {
1713
 
            rotateLeft();
1714
 
        }
1715
 
        else if(event->delta() < 0)
1716
 
        {
1717
 
            rotateRight();
1718
 
        }
1719
 
    }
1720
 
    else if(event->modifiers() == Qt::AltModifier)
1721
 
    {
1722
 
        QWheelEvent wheelEvent(*event);
1723
 
        wheelEvent.setModifiers(Qt::NoModifier);
1724
 
 
1725
 
        QApplication::sendEvent(m_view->horizontalScrollBar(), &wheelEvent);
1726
 
    }
1727
 
}
1728
 
 
1729
 
void DocumentView::slotUpdatePageItem(int index)
1730
 
{
1731
 
    PageItem* pageItem = m_pagesByIndex.value(index, 0);
1732
 
 
1733
 
    if(pageItem != 0)
1734
 
    {
1735
 
        pageItem->update(pageItem->boundingRect());
1736
 
    }
1737
 
}
1738
 
 
1739
 
void DocumentView::slotUpdateThumbnailItem(int index)
1740
 
{
1741
 
    ThumbnailItem* thumbnailItem = m_thumbnailsByIndex.value(index, 0);
1742
 
 
1743
 
    if(thumbnailItem != 0)
1744
 
    {
1745
 
        thumbnailItem->update(thumbnailItem->boundingRect());
1746
 
    }
1747
 
}
1748
 
 
1749
 
void DocumentView::slotVerticalScrollBarValueChanged(int value)
1750
 
{
1751
 
    if(m_pageLayout == OneColumn || m_pageLayout == TwoColumns)
1752
 
    {
1753
 
        QMap< qreal, PageItem* >::const_iterator iterator = --m_pagesByHeight.lowerBound(value + 0.5 * m_view->verticalScrollBar()->pageStep());
1754
 
 
1755
 
        if(iterator != m_pagesByHeight.end())
1756
 
        {
1757
 
            if(m_currentPage != iterator.value()->m_index + 1)
1758
 
            {
1759
 
                m_currentPage = iterator.value()->m_index + 1;
1760
 
 
1761
 
                emit currentPageChanged(m_currentPage);
1762
 
            }
1763
 
        }
1764
 
    }
1765
 
}
1766
 
 
1767
 
void DocumentView::slotThumbnailsEnsureVisible(int currentPage)
1768
 
{
1769
 
    ThumbnailItem* thumbnailItem = m_thumbnailsByIndex.value(currentPage - 1, 0);
1770
 
 
1771
 
    if(thumbnailItem != 0)
1772
 
    {
1773
 
        m_thumbnailsGraphicsView->ensureVisible(thumbnailItem);
1774
 
    }
1775
 
}
1776
 
 
1777
 
void DocumentView::slotPrefetchTimerTimeout()
1778
 
{
1779
 
#ifndef RENDER_IN_PAINT
1780
 
 
1781
 
    int fromPage = -1, toPage = -1;
1782
 
 
1783
 
    switch(m_pageLayout)
1784
 
    {
1785
 
    case OnePage:
1786
 
    case OneColumn:
1787
 
        fromPage = m_currentPage - 1;
1788
 
        toPage = m_currentPage + 2;
1789
 
 
1790
 
        break;
1791
 
    case TwoPages:
1792
 
    case TwoColumns:
1793
 
        fromPage = m_currentPage - 2;
1794
 
        toPage = m_currentPage + 4;
1795
 
 
1796
 
        break;
1797
 
    }
1798
 
 
1799
 
    fromPage = qMax(fromPage, 1);
1800
 
    toPage = qMin(toPage, m_numberOfPages);
1801
 
 
1802
 
    for(int page = fromPage; page <= toPage; page++)
1803
 
    {
1804
 
        PageItem* pageItem = m_pagesByIndex.value(page - 1, 0);
1805
 
 
1806
 
        if(pageItem != 0)
1807
 
        {
1808
 
            m_pageCacheMutex.lock();
1809
 
 
1810
 
            PageCacheKey key(pageItem->m_index, pageItem->m_scale * m_resolutionX, pageItem->m_scale * m_resolutionY);
1811
 
 
1812
 
            if(!m_pageCache.contains(key))
1813
 
            {
1814
 
                if(!pageItem->m_render.isRunning())
1815
 
                {
1816
 
                    pageItem->m_render = QtConcurrent::run(pageItem, &DocumentView::PageItem::render, pageItem->m_scale, true);
1817
 
                }
1818
 
            }
1819
 
 
1820
 
            m_pageCacheMutex.unlock();
1821
 
        }
1822
 
    }
1823
 
 
1824
 
#endif
1825
 
}
1826
 
 
1827
 
void DocumentView::slotBookmarksMenuEntrySelected(int page, int value)
1828
 
{
1829
 
    setCurrentPage(page);
1830
 
 
1831
 
    m_view->verticalScrollBar()->setValue(value);
1832
 
}
1833
 
 
1834
 
void DocumentView::slotTabActionTriggered()
1835
 
{
1836
 
    TabWidget* tabWidget = qobject_cast< TabWidget* >(this->parent()->parent()); Q_ASSERT(tabWidget);
1837
 
 
1838
 
    tabWidget->setCurrentIndex(tabWidget->indexOf(this));
1839
 
}
1840
 
 
1841
 
void DocumentView::slotOutlineTreeWidgetItemClicked(QTreeWidgetItem* item, int column)
1842
 
{
1843
 
    setCurrentPage(item->data(column, Qt::UserRole).toInt(), item->data(column, Qt::UserRole+1).toReal());
1844
 
}
1845
 
 
1846
 
void DocumentView::search(const QString& text, bool matchCase)
1847
 
{
1848
 
    QList<int> indices;
1849
 
 
1850
 
    for(int index = m_currentPage - 1; index < m_numberOfPages; index++)
1851
 
    {
1852
 
        indices.append(index);
1853
 
    }
1854
 
 
1855
 
    for(int index = 0; index < m_currentPage - 1; index++)
1856
 
    {
1857
 
        indices.append(index);
1858
 
    }
1859
 
 
1860
 
    bool firstResult = true;
1861
 
 
1862
 
    emit searchProgressed(0);
1863
 
 
1864
 
    foreach(int index, indices)
1865
 
    {
1866
 
        if(m_search.isCanceled())
1867
 
        {
1868
 
            emit searchCanceled();
1869
 
 
1870
 
            return;
1871
 
        }
1872
 
 
1873
 
        m_documentMutex.lock();
1874
 
 
1875
 
        Poppler::Page* page = m_document->page(index);
1876
 
 
1877
 
        QList< QRectF > results;
1878
 
 
1879
 
#ifdef HAS_POPPLER_14
1880
 
        double rectLeft = 0.0, rectTop = 0.0, rectRight = 0.0, rectBottom = 0.0;
1881
 
 
1882
 
        while(page->search(text, rectLeft, rectTop, rectRight, rectBottom, Poppler::Page::NextResult, matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive))
1883
 
        {
1884
 
            QRectF rect;
1885
 
            rect.setLeft(rectLeft);
1886
 
            rect.setTop(rectTop);
1887
 
            rect.setRight(rectRight);
1888
 
            rect.setBottom(rectBottom);
1889
 
 
1890
 
            results.append(rect.normalized());
1891
 
        }
1892
 
#else
1893
 
        QRectF rect;
1894
 
 
1895
 
        while(page->search(text, rect, Poppler::Page::NextResult, matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive))
1896
 
        {
1897
 
            results.append(rect.normalized());
1898
 
        }
1899
 
#endif
1900
 
 
1901
 
        delete page;
1902
 
 
1903
 
        m_documentMutex.unlock();
1904
 
 
1905
 
        m_resultsMutex.lock();
1906
 
 
1907
 
        while(!results.isEmpty())
1908
 
        {
1909
 
            m_results.insertMulti(index, results.takeLast());
1910
 
        }
1911
 
 
1912
 
        if(m_results.contains(index) && firstResult)
1913
 
        {
1914
 
            emit firstResultFound();
1915
 
 
1916
 
            firstResult = false;
1917
 
        }
1918
 
 
1919
 
        m_resultsMutex.unlock();
1920
 
 
1921
 
        if(m_highlightAll)
1922
 
        {
1923
 
            emit pageItemChanged(index);
1924
 
        }
1925
 
 
1926
 
        emit searchProgressed((100 * (indices.indexOf(index) + 1)) / indices.count());
1927
 
    }
1928
 
 
1929
 
    emit searchFinished();
1930
 
}
1931
 
 
1932
 
void DocumentView::print(QPrinter* printer, int fromPage, int toPage)
1933
 
{
1934
 
#ifdef WITH_CUPS
1935
 
 
1936
 
    emit printProgressed(0);
1937
 
 
1938
 
    int num_dests = 0;
1939
 
    cups_dest_t* dests = 0;
1940
 
 
1941
 
    num_dests = cupsGetDests(&dests);
1942
 
 
1943
 
    cups_dest_t* dest = 0;
1944
 
 
1945
 
    dest = cupsGetDest(printer->printerName().toLocal8Bit(), 0, num_dests, dests);
1946
 
 
1947
 
    if(dest != 0)
1948
 
    {
1949
 
        int num_options = 0;
1950
 
        cups_option_t* options = 0;
1951
 
 
1952
 
        for(int i = 0; i < dest->num_options; i++)
1953
 
        {
1954
 
            num_options = cupsAddOption(dest->options[i].name, dest->options[i].value, num_options, &options);
1955
 
        }
1956
 
 
1957
 
        // page layout and range
1958
 
 
1959
 
        switch(m_pageLayout)
1960
 
        {
1961
 
        case OnePage:
1962
 
        case OneColumn:
1963
 
            num_options = cupsAddOption("number-up", QString("%1").arg(1).toLocal8Bit(), num_options, &options);
1964
 
            num_options = cupsAddOption("page-ranges", QString("%1-%2").arg(fromPage).arg(toPage).toLocal8Bit(), num_options, &options);
1965
 
 
1966
 
            break;
1967
 
        case TwoPages:
1968
 
        case TwoColumns:
1969
 
            num_options = cupsAddOption("number-up", QString("%1").arg(2).toLocal8Bit(), num_options, &options);
1970
 
            num_options = cupsAddOption("page-ranges", QString("%1-%2").arg(fromPage % 2 == 0 ? fromPage / 2 : (fromPage + 1) / 2).arg(toPage % 2 == 0 ? toPage / 2 : (toPage + 1) / 2).toLocal8Bit(), num_options, &options);
1971
 
 
1972
 
            break;
1973
 
        }
1974
 
 
1975
 
        // copy count
1976
 
 
1977
 
        num_options = cupsAddOption("copies", QString("%1").arg(printer->copyCount()).toLocal8Bit(), num_options, &options);
1978
 
 
1979
 
        // collate copies
1980
 
 
1981
 
        num_options = cupsAddOption("collate", QString("%1").arg(printer->collateCopies()).toLocal8Bit(), num_options, &options);
1982
 
 
1983
 
        // duplex
1984
 
 
1985
 
        switch(printer->duplex())
1986
 
        {
1987
 
        case QPrinter::DuplexNone:
1988
 
            num_options = cupsAddOption("sides", "one-sided", num_options, &options); break;
1989
 
        case QPrinter::DuplexAuto:
1990
 
            break;
1991
 
        case QPrinter::DuplexLongSide:
1992
 
            num_options = cupsAddOption("sides", "two-sided-long-edge", num_options, &options); break;
1993
 
        case QPrinter::DuplexShortSide:
1994
 
            num_options = cupsAddOption("sides", "two-sided-short-edge", num_options, &options); break;
1995
 
        }
1996
 
 
1997
 
        // page order
1998
 
 
1999
 
        switch(printer->pageOrder())
2000
 
        {
2001
 
        case QPrinter::FirstPageFirst:
2002
 
            num_options = cupsAddOption("outputorder", "normal", num_options, &options); break;
2003
 
        case QPrinter::LastPageFirst:
2004
 
            num_options = cupsAddOption("outputorder", "reverse", num_options, &options); break;
2005
 
        }
2006
 
 
2007
 
        // color mode
2008
 
 
2009
 
        switch(printer->colorMode())
2010
 
        {
2011
 
        case QPrinter::Color:
2012
 
            break;
2013
 
        case QPrinter::GrayScale:
2014
 
            num_options = cupsAddOption("ColorModel", "Gray", num_options, &options); break;
2015
 
        }
2016
 
 
2017
 
        QFileInfo fileInfo(m_filePath);
2018
 
 
2019
 
        int jobId = cupsPrintFile(dest->name, fileInfo.absoluteFilePath().toLocal8Bit(), fileInfo.completeBaseName().toLocal8Bit(), num_options, options);
2020
 
 
2021
 
        cupsFreeDests(num_dests, dests);
2022
 
        cupsFreeOptions(num_options, options);
2023
 
 
2024
 
        if(jobId < 1)
2025
 
        {
2026
 
            qDebug() << "CUPS:" << cupsLastErrorString();
2027
 
        }
2028
 
    }
2029
 
    else
2030
 
    {
2031
 
        qDebug() << "CUPS:" << cupsLastErrorString();
2032
 
    }
2033
 
 
2034
 
    delete printer;
2035
 
 
2036
 
    emit printProgressed(100);
2037
 
 
2038
 
    emit printFinished();
2039
 
 
2040
 
#else
2041
 
 
2042
 
    printer->setFullPage(true);
2043
 
 
2044
 
    QPainter* painter = new QPainter(printer);
2045
 
 
2046
 
    emit printProgressed(0);
2047
 
 
2048
 
    for(int index = fromPage - 1; index <= toPage - 1; index++)
2049
 
    {
2050
 
        if(m_print.isCanceled())
2051
 
        {
2052
 
            emit printCanceled();
2053
 
 
2054
 
            delete painter;
2055
 
            delete printer;
2056
 
            return;
2057
 
        }
2058
 
 
2059
 
        m_documentMutex.lock();
2060
 
 
2061
 
        Poppler::Page* page = m_document->page(index);
2062
 
 
2063
 
        qreal fitToWidth = printer->width() / (printer->physicalDpiX() / 72.0 * page->pageSizeF().width());
2064
 
        qreal fitToHeight = printer->height() / (printer->physicalDpiY() / 72.0 * page->pageSizeF().height());
2065
 
        qreal fit = qMin(fitToWidth, fitToHeight);
2066
 
 
2067
 
        QImage image = page->renderToImage(printer->physicalDpiX(), printer->physicalDpiY());
2068
 
 
2069
 
        delete page;
2070
 
 
2071
 
        m_documentMutex.unlock();
2072
 
 
2073
 
        painter->setTransform(QTransform::fromScale(fit, fit));
2074
 
        painter->drawImage(0.0, 0.0, image);
2075
 
 
2076
 
        if(index < toPage - 1)
2077
 
        {
2078
 
            printer->newPage();
2079
 
        }
2080
 
 
2081
 
        emit printProgressed((100 * (index + 1 - fromPage + 1)) / (toPage - fromPage + 1));
2082
 
    }
2083
 
 
2084
 
    emit printFinished();
2085
 
 
2086
 
    delete painter;
2087
 
    delete printer;
2088
 
 
2089
 
#endif // WITH_CUPS
2090
 
}
2091
 
 
2092
 
void DocumentView::clearScene()
2093
 
{
2094
 
    m_pagesByIndex.clear();
2095
 
    m_thumbnailsByIndex.clear();
2096
 
 
2097
 
    m_scene->removeItem(m_highlight);
2098
 
    m_scene->clear();
2099
 
    m_scene->addItem(m_highlight);
2100
 
 
2101
 
    m_thumbnailsGraphicsView->scene()->clear();
2102
 
}
2103
 
 
2104
 
void DocumentView::clearPageCache()
2105
 
{
2106
 
    m_pageCacheMutex.lock();
2107
 
 
2108
 
    m_pageCache.clear();
2109
 
    m_pageCacheSize = 0u;
2110
 
    m_maximumPageCacheSize = m_settings.value("documentView/maximumPageCacheSize", 33554432u).toUInt();
2111
 
 
2112
 
    m_pageCacheMutex.unlock();
2113
 
}
2114
 
 
2115
 
void DocumentView::updatePageCache(const DocumentView::PageCacheKey& key, const DocumentView::PageCacheValue& value)
2116
 
{
2117
 
    m_pageCacheMutex.lock();
2118
 
 
2119
 
    uint byteCount = value.image.byteCount();
2120
 
 
2121
 
    if(m_maximumPageCacheSize < 3 * byteCount)
2122
 
    {
2123
 
        m_maximumPageCacheSize = 3 * byteCount;
2124
 
 
2125
 
        qWarning() << tr("Maximum page cache size is too small. Increased it to %1 bytes to hold at least three pages.").arg(3 * byteCount);
2126
 
    }
2127
 
 
2128
 
    while(m_pageCacheSize + byteCount > m_maximumPageCacheSize)
2129
 
    {
2130
 
        QMap< DocumentView::PageCacheKey, DocumentView::PageCacheValue >::const_iterator first = m_pageCache.begin();
2131
 
        QMap< DocumentView::PageCacheKey, DocumentView::PageCacheValue >::const_iterator last = --m_pageCache.end();
2132
 
 
2133
 
        if(first.value().time < last.value().time)
2134
 
        {
2135
 
            m_pageCacheSize -= first.value().image.byteCount();
2136
 
            m_pageCache.remove(first.key());
2137
 
        }
2138
 
        else
2139
 
        {
2140
 
            m_pageCacheSize -= last.value().image.byteCount();
2141
 
            m_pageCache.remove(last.key());
2142
 
        }
2143
 
    }
2144
 
 
2145
 
    m_pageCacheSize += byteCount;
2146
 
    m_pageCache.insert(key, value);
2147
 
 
2148
 
    m_pageCacheMutex.unlock();
2149
 
}
2150
 
 
2151
 
void DocumentView::preparePages()
2152
 
{
2153
 
    m_scene->removeItem(m_highlight);
2154
 
    m_scene->clear();
2155
 
    m_scene->addItem(m_highlight);
2156
 
 
2157
 
    m_pagesByIndex.clear();
2158
 
    m_pagesByIndex.reserve(m_numberOfPages);
2159
 
 
2160
 
    for(int index = 0; index < m_numberOfPages; index++)
2161
 
    {
2162
 
        PageItem* pageItem = new PageItem();
2163
 
 
2164
 
        pageItem->m_index = index;
2165
 
        pageItem->m_page = m_document->page(pageItem->m_index);
2166
 
        pageItem->m_size = pageItem->m_page->pageSizeF();
2167
 
 
2168
 
        foreach(Poppler::Link* link, pageItem->m_page->links())
2169
 
        {
2170
 
            if(link->linkType() == Poppler::Link::Goto)
2171
 
            {
2172
 
                if(!static_cast< Poppler::LinkGoto* >(link)->isExternal())
2173
 
                {
2174
 
                    QRectF area = link->linkArea().normalized();
2175
 
                    int page = static_cast< Poppler::LinkGoto* >(link)->destination().pageNumber();
2176
 
                    qreal top = static_cast< Poppler::LinkGoto* >(link)->destination().isChangeTop() ? static_cast< Poppler::LinkGoto* >(link)->destination().top() : 0.0;
2177
 
 
2178
 
                    page = qMax(page, 1);
2179
 
                    page = qMin(page, m_numberOfPages);
2180
 
 
2181
 
                    top = qMax(top, static_cast< qreal >(0.0));
2182
 
                    top = qMin(top, static_cast< qreal >(1.0));
2183
 
 
2184
 
                    pageItem->m_links.append(Link(area, page, top));
2185
 
                }
2186
 
            }
2187
 
            else if(link->linkType() == Poppler::Link::Browse)
2188
 
            {
2189
 
                QRectF area = link->linkArea().normalized();
2190
 
                QString url = static_cast< Poppler::LinkBrowse* >(link)->url();
2191
 
 
2192
 
                pageItem->m_links.append(Link(area, url));
2193
 
            }
2194
 
 
2195
 
            delete link;
2196
 
        }
2197
 
 
2198
 
        m_scene->addItem(pageItem);
2199
 
 
2200
 
        m_pagesByIndex.append(pageItem);
2201
 
    }
2202
 
}
2203
 
 
2204
 
void DocumentView::prepareOutline()
2205
 
{
2206
 
    m_outlineTreeWidget->clear();
2207
 
 
2208
 
    QDomDocument* toc = m_document->toc();
2209
 
 
2210
 
    if(toc != 0)
2211
 
    {
2212
 
        prepareOutline(toc->firstChild(), 0, 0);
2213
 
 
2214
 
        delete toc;
2215
 
    }
2216
 
}
2217
 
 
2218
 
void DocumentView::prepareOutline(const QDomNode& node, QTreeWidgetItem* parent, QTreeWidgetItem* sibling)
2219
 
{
2220
 
    QDomElement element = node.toElement();
2221
 
 
2222
 
    QTreeWidgetItem* item = 0;
2223
 
 
2224
 
    if(parent != 0)
2225
 
    {
2226
 
        item = new QTreeWidgetItem(parent);
2227
 
    }
2228
 
    else
2229
 
    {
2230
 
        item = new QTreeWidgetItem(m_outlineTreeWidget, sibling);
2231
 
    }
2232
 
 
2233
 
    item->setText(0, element.tagName());
2234
 
    item->setToolTip(0, element.tagName());
2235
 
 
2236
 
    if(element.hasAttribute("Destination"))
2237
 
    {
2238
 
        Poppler::LinkDestination linkDestination(element.attribute("Destination"));
2239
 
 
2240
 
        int page = linkDestination.pageNumber();
2241
 
        qreal top = linkDestination.isChangeTop() ? linkDestination.top() : 0.0;
2242
 
 
2243
 
        page = qMax(page, 1);
2244
 
        page = qMin(page, m_numberOfPages);
2245
 
 
2246
 
        top = qMax(top, static_cast< qreal >(0.0));
2247
 
        top = qMin(top, static_cast< qreal >(1.0));
2248
 
 
2249
 
        item->setData(0, Qt::UserRole, page);
2250
 
        item->setData(0, Qt::UserRole+1, top);
2251
 
    }
2252
 
    else if(element.hasAttribute("DestinationName"))
2253
 
    {
2254
 
        Poppler::LinkDestination* linkDestination = m_document->linkDestination(element.attribute("DestinationName"));
2255
 
 
2256
 
        int page = linkDestination != 0 ? linkDestination->pageNumber() : 1;
2257
 
        qreal top = linkDestination != 0 ? (linkDestination->isChangeTop() ? linkDestination->top() : 0.0) : 0.0;
2258
 
 
2259
 
        page = qMax(page, 1);
2260
 
        page = qMin(page, m_numberOfPages);
2261
 
 
2262
 
        top = qMax(top, static_cast< qreal >(0.0));
2263
 
        top = qMin(top, static_cast< qreal >(1.0));
2264
 
 
2265
 
        item->setData(0, Qt::UserRole, page);
2266
 
        item->setData(0, Qt::UserRole+1, top);
2267
 
 
2268
 
        delete linkDestination;
2269
 
    }
2270
 
    else
2271
 
    {
2272
 
        item->setData(0, Qt::UserRole, -1);
2273
 
    }
2274
 
 
2275
 
    if(QVariant(element.attribute("Open", "false")).toBool())
2276
 
    {
2277
 
        m_outlineTreeWidget->expandItem(item);
2278
 
    }
2279
 
 
2280
 
    QDomNode siblingNode = node.nextSibling();
2281
 
    if(!siblingNode.isNull())
2282
 
    {
2283
 
        prepareOutline(siblingNode, parent, item);
2284
 
    }
2285
 
 
2286
 
    QDomNode childNode = node.firstChild();
2287
 
    if(!childNode.isNull())
2288
 
    {
2289
 
        prepareOutline(childNode, item, 0);
2290
 
    }
2291
 
}
2292
 
 
2293
 
void DocumentView::prepareMetaInformation()
2294
 
{
2295
 
    m_metaInformationTableWidget->clear();
2296
 
 
2297
 
    QStringList keys = m_document->infoKeys();
2298
 
 
2299
 
    m_metaInformationTableWidget->setRowCount(keys.count());
2300
 
    m_metaInformationTableWidget->setColumnCount(2);
2301
 
 
2302
 
    for(int index = 0; index < keys.count(); index++)
2303
 
    {
2304
 
        QString key = keys.at(index);
2305
 
        QString value = m_document->info(key);
2306
 
 
2307
 
        if(value.startsWith("D:"))
2308
 
        {
2309
 
            value = QLocale::system().toString(m_document->date(key));
2310
 
        }
2311
 
 
2312
 
        m_metaInformationTableWidget->setItem(index, 0, new QTableWidgetItem(key));
2313
 
        m_metaInformationTableWidget->setItem(index, 1, new QTableWidgetItem(value));
2314
 
    }
2315
 
}
2316
 
 
2317
 
void DocumentView::prepareThumbnails()
2318
 
{
2319
 
    m_thumbnailsGraphicsView->scene()->clear();
2320
 
 
2321
 
    m_thumbnailsByIndex.clear();
2322
 
    m_thumbnailsByIndex.reserve(m_numberOfPages);
2323
 
 
2324
 
    qreal sceneWidth = 0.0, sceneHeight = thumbnailSpacing;
2325
 
 
2326
 
    for(int index = 0; index < m_numberOfPages; index++)
2327
 
    {
2328
 
        ThumbnailItem* thumbnailItem = new ThumbnailItem();
2329
 
 
2330
 
        thumbnailItem->m_index = index;
2331
 
        thumbnailItem->m_page = m_document->page(thumbnailItem->m_index);
2332
 
        thumbnailItem->m_size = thumbnailItem->m_page->pageSizeF();
2333
 
 
2334
 
        thumbnailItem->m_scale = qMin(
2335
 
                    thumbnailWidth / (physicalDpiX() / 72.0 * thumbnailItem->m_size.width()),
2336
 
                    thumbnailHeight / (physicalDpiY() / 72.0 * thumbnailItem->m_size.height()));
2337
 
 
2338
 
        thumbnailItem->setPos(thumbnailSpacing, sceneHeight);
2339
 
 
2340
 
        m_thumbnailsGraphicsView->scene()->addItem(thumbnailItem);
2341
 
 
2342
 
        m_thumbnailsByIndex.append(thumbnailItem);
2343
 
 
2344
 
        sceneWidth = qMax(sceneWidth, thumbnailItem->boundingRect().width() + 2 * thumbnailSpacing);
2345
 
        sceneHeight += thumbnailItem->boundingRect().height() + thumbnailSpacing;
2346
 
 
2347
 
        QGraphicsSimpleTextItem* textItem = new QGraphicsSimpleTextItem(QLocale::system().toString(index + 1));
2348
 
 
2349
 
        textItem->setPos(2 * thumbnailSpacing, sceneHeight);
2350
 
 
2351
 
        m_thumbnailsGraphicsView->scene()->addItem(textItem);
2352
 
 
2353
 
        sceneWidth = qMax(sceneWidth, textItem->boundingRect().width() + 3 * thumbnailSpacing);
2354
 
        sceneHeight += textItem->boundingRect().height() + thumbnailSpacing;
2355
 
    }
2356
 
 
2357
 
    m_thumbnailsGraphicsView->scene()->setSceneRect(0.0, 0.0, sceneWidth, sceneHeight);
2358
 
    m_thumbnailsGraphicsView->setSceneRect(0.0, 0.0, sceneWidth, sceneHeight);
2359
 
 
2360
 
    m_thumbnailsGraphicsView->setMinimumWidth(sceneWidth + 35);
2361
 
}
2362
 
 
2363
 
void DocumentView::prepareScene()
2364
 
{
2365
 
    // calculate scale
2366
 
 
2367
 
    switch(m_rotation)
2368
 
    {
2369
 
    case RotateBy0:
2370
 
    case RotateBy180:
2371
 
        m_resolutionX = physicalDpiX();
2372
 
        m_resolutionY = physicalDpiY();
2373
 
 
2374
 
        break;
2375
 
    case RotateBy90:
2376
 
    case RotateBy270:
2377
 
        m_resolutionX = physicalDpiY();
2378
 
        m_resolutionY = physicalDpiX();
2379
 
 
2380
 
        break;
2381
 
    }
2382
 
 
2383
 
    if(m_scaleMode == FitToPage || m_scaleMode == FitToPageWidth)
2384
 
    {
2385
 
        qreal pageWidth = 0.0, pageHeight = 0.0;
2386
 
        qreal visibleWidth = m_view->viewport()->width() - 5;
2387
 
        qreal visibleHeight = m_view->viewport()->height() - 5;
2388
 
 
2389
 
        switch(m_pageLayout)
2390
 
        {
2391
 
        case OnePage:
2392
 
        case OneColumn:
2393
 
            for(int index = 0; index < m_numberOfPages; index++)
2394
 
            {
2395
 
                PageItem* pageItem = m_pagesByIndex.at(index);
2396
 
 
2397
 
                switch(m_rotation)
2398
 
                {
2399
 
                case RotateBy0:
2400
 
                case RotateBy180:
2401
 
                    pageWidth = m_resolutionX / 72.0 * pageItem->m_size.width();
2402
 
                    pageHeight = m_resolutionY / 72.0 * pageItem->m_size.height();
2403
 
 
2404
 
                    break;
2405
 
                case RotateBy90:
2406
 
                case RotateBy270:
2407
 
                    pageWidth = m_resolutionY / 72.0 * pageItem->m_size.height();
2408
 
                    pageHeight = m_resolutionX / 72.0 * pageItem->m_size.width();
2409
 
 
2410
 
                    break;
2411
 
                }
2412
 
 
2413
 
                qreal scale = (visibleWidth - 2 * pageSpacing) / pageWidth;
2414
 
                if(m_scaleMode == FitToPage)
2415
 
                {
2416
 
                    scale = qMin(scale, (visibleHeight - 2 * pageSpacing) / pageHeight);
2417
 
                }
2418
 
 
2419
 
                pageItem->m_scale = scale;
2420
 
            }
2421
 
 
2422
 
            break;
2423
 
        case TwoPages:
2424
 
        case TwoColumns:
2425
 
            for(int index = 0; index < (m_numberOfPages % 2 == 0 ? m_numberOfPages : m_numberOfPages - 1); index += 2)
2426
 
            {
2427
 
                PageItem* leftPageItem = m_pagesByIndex.at(index);
2428
 
                PageItem* rightPageItem = m_pagesByIndex.at(index + 1);
2429
 
 
2430
 
                if(fitToEqualWidth)
2431
 
                {
2432
 
                    switch(m_rotation)
2433
 
                    {
2434
 
                    case RotateBy0:
2435
 
                    case RotateBy180:
2436
 
                        pageWidth = m_resolutionX / 72.0 * 2.0 * qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width());
2437
 
                        pageHeight = m_resolutionY / 72.0 * qMax(
2438
 
                                    qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width()) / leftPageItem->m_size.width() * leftPageItem->m_size.height(),
2439
 
                                    qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width()) / rightPageItem->m_size.width() * rightPageItem->m_size.height());
2440
 
 
2441
 
                        break;
2442
 
                    case RotateBy90:
2443
 
                    case RotateBy270:
2444
 
                        pageWidth = m_resolutionY / 72.0 * 2.0 * qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height());
2445
 
                        pageHeight = m_resolutionX / 72.0 * qMax(
2446
 
                                    qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height()) / leftPageItem->m_size.height() * leftPageItem->m_size.width(),
2447
 
                                    qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height()) / rightPageItem->m_size.height() * rightPageItem->m_size.width());
2448
 
 
2449
 
                        break;
2450
 
                    }
2451
 
 
2452
 
                    qreal scale = (visibleWidth - 3 * pageSpacing) / pageWidth;
2453
 
                    if(m_scaleMode == FitToPage)
2454
 
                    {
2455
 
                        scale = qMin(scale, (visibleHeight - 2 * pageSpacing) / pageHeight);
2456
 
                    }
2457
 
 
2458
 
                    switch(m_rotation)
2459
 
                    {
2460
 
                    case RotateBy0:
2461
 
                    case RotateBy180:
2462
 
                        leftPageItem->m_scale = scale * qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width()) / leftPageItem->m_size.width();
2463
 
                        rightPageItem->m_scale = scale * qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width()) / rightPageItem->m_size.width();
2464
 
 
2465
 
                        break;
2466
 
                    case RotateBy90:
2467
 
                    case RotateBy270:
2468
 
                        leftPageItem->m_scale = scale * qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height()) / leftPageItem->m_size.height();
2469
 
                        rightPageItem->m_scale = scale * qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height()) / rightPageItem->m_size.height();
2470
 
 
2471
 
                        break;
2472
 
                    }
2473
 
                }
2474
 
                else
2475
 
                {
2476
 
                    switch(m_rotation)
2477
 
                    {
2478
 
                    case RotateBy0:
2479
 
                    case RotateBy180:
2480
 
                        pageWidth = m_resolutionX / 72.0 * (leftPageItem->m_size.width() + rightPageItem->m_size.width());
2481
 
                        pageHeight = m_resolutionY / 72.0 * qMax(leftPageItem->m_size.height(), rightPageItem->m_size.height());
2482
 
 
2483
 
                        break;
2484
 
                    case RotateBy90:
2485
 
                    case RotateBy270:
2486
 
                        pageWidth = m_resolutionY / 72.0 * (leftPageItem->m_size.height() + rightPageItem->m_size.height());
2487
 
                        pageHeight = m_resolutionX / 72.0 * qMax(leftPageItem->m_size.width(), rightPageItem->m_size.width());
2488
 
 
2489
 
                        break;
2490
 
                    }
2491
 
 
2492
 
                    qreal scale = (visibleWidth - 3 * pageSpacing) / pageWidth;
2493
 
                    if(m_scaleMode == FitToPage)
2494
 
                    {
2495
 
                        scale = qMin(scale, (visibleHeight - 2 * pageSpacing) / pageHeight);
2496
 
                    }
2497
 
 
2498
 
                    leftPageItem->m_scale = scale;
2499
 
                    rightPageItem->m_scale = scale;
2500
 
                }
2501
 
            }
2502
 
 
2503
 
            if(m_numberOfPages % 2 != 0)
2504
 
            {
2505
 
                PageItem* leftPageItem = m_pagesByIndex.at(m_numberOfPages - 1);
2506
 
 
2507
 
                switch(m_rotation)
2508
 
                {
2509
 
                case RotateBy0:
2510
 
                case RotateBy180:
2511
 
                    pageWidth = m_resolutionX / 72.0 * leftPageItem->m_size.width();
2512
 
                    pageHeight = m_resolutionY / 72.0 * leftPageItem->m_size.height();
2513
 
 
2514
 
                    break;
2515
 
                case RotateBy90:
2516
 
                case RotateBy270:
2517
 
                    pageWidth = m_resolutionY / 72.0 * leftPageItem->m_size.height();
2518
 
                    pageHeight = m_resolutionX / 72.0 * leftPageItem->m_size.width();
2519
 
 
2520
 
                    break;
2521
 
                }
2522
 
 
2523
 
                qreal scale = (visibleWidth - 2 * pageSpacing) / pageWidth;
2524
 
                if(m_scaleMode == FitToPage)
2525
 
                {
2526
 
                    scale = qMin(scale, (visibleHeight - 2 * pageSpacing) / pageHeight);
2527
 
                }
2528
 
 
2529
 
                leftPageItem->m_scale = scale;
2530
 
            }
2531
 
 
2532
 
            break;
2533
 
        }
2534
 
    }
2535
 
    else if(m_scaleMode == DoNotScale || m_scaleMode == ScaleFactor)
2536
 
    {
2537
 
        foreach(PageItem* pageItem, m_pagesByIndex)
2538
 
        {
2539
 
            pageItem->m_scale = m_scaleMode == DoNotScale ? 1.0 : m_scaleFactor;
2540
 
        }
2541
 
    }
2542
 
 
2543
 
    // calculate transformations
2544
 
 
2545
 
    m_pageTransform.reset();
2546
 
 
2547
 
    switch(m_rotation)
2548
 
    {
2549
 
    case RotateBy0:
2550
 
        m_pageTransform.rotate(0.0); break;
2551
 
    case RotateBy90:
2552
 
        m_pageTransform.rotate(90.0); break;
2553
 
    case RotateBy180:
2554
 
        m_pageTransform.rotate(180.0); break;
2555
 
    case RotateBy270:
2556
 
        m_pageTransform.rotate(270.0); break;
2557
 
    }
2558
 
 
2559
 
    foreach(PageItem* pageItem, m_pagesByIndex)
2560
 
    {
2561
 
        pageItem->prepareGeometryChange();
2562
 
 
2563
 
        pageItem->m_linkTransform.reset();
2564
 
        pageItem->m_linkTransform.scale(pageItem->m_scale * m_resolutionX / 72.0 * pageItem->m_size.width(), pageItem->m_scale * m_resolutionY / 72.0 * pageItem->m_size.height());
2565
 
 
2566
 
        pageItem->m_highlightTransform.reset();
2567
 
        pageItem->m_highlightTransform.scale(pageItem->m_scale * m_resolutionX / 72.0, pageItem->m_scale * m_resolutionY / 72.0);
2568
 
 
2569
 
        switch(m_rotation)
2570
 
        {
2571
 
        case RotateBy0:
2572
 
            pageItem->setRotation(0.0); break;
2573
 
        case RotateBy90:
2574
 
            pageItem->setRotation(90.0); break;
2575
 
        case RotateBy180:
2576
 
            pageItem->setRotation(180.0); break;
2577
 
        case RotateBy270:
2578
 
            pageItem->setRotation(270.0); break;
2579
 
        }
2580
 
    }
2581
 
 
2582
 
    // calculate layout
2583
 
 
2584
 
    disconnect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
2585
 
 
2586
 
    m_pagesByHeight.clear();
2587
 
    m_bookmarksMenu->clearList();
2588
 
 
2589
 
    qreal sceneWidth = 0.0, sceneHeight = pageSpacing;
2590
 
 
2591
 
    switch(m_pageLayout)
2592
 
    {
2593
 
    case OnePage:
2594
 
    case OneColumn:
2595
 
        for(int index = 0; index < m_numberOfPages; index++)
2596
 
        {
2597
 
            PageItem* pageItem = m_pagesByIndex.at(index);
2598
 
            QRectF rect = m_pageTransform.mapRect(pageItem->boundingRect());
2599
 
 
2600
 
            pageItem->setPos(pageSpacing - rect.left(), sceneHeight - rect.top());
2601
 
            m_pagesByHeight.insert(sceneHeight, pageItem);
2602
 
 
2603
 
            sceneWidth = qMax(sceneWidth, rect.width() + 2 * pageSpacing);
2604
 
            sceneHeight += rect.height() + pageSpacing;
2605
 
        }
2606
 
 
2607
 
        break;
2608
 
    case TwoPages:
2609
 
    case TwoColumns:
2610
 
        for(int index = 0; index < (m_numberOfPages % 2 == 0 ? m_numberOfPages : m_numberOfPages - 1); index += 2)
2611
 
        {
2612
 
            PageItem* leftPageItem = m_pagesByIndex.at(index);
2613
 
            PageItem* rightPageItem = m_pagesByIndex.at(index + 1);
2614
 
            QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect());
2615
 
            QRectF rightRect = m_pageTransform.mapRect(rightPageItem->boundingRect());
2616
 
 
2617
 
            leftPageItem->setPos(pageSpacing - leftRect.left(), sceneHeight - leftRect.top());
2618
 
            rightPageItem->setPos(2 * pageSpacing + leftRect.width() - rightRect.left(), sceneHeight - rightRect.top());
2619
 
            m_pagesByHeight.insert(sceneHeight, leftPageItem);
2620
 
 
2621
 
            sceneWidth = qMax(sceneWidth, leftRect.width() + rightRect.width() + 3 * pageSpacing);
2622
 
            sceneHeight += qMax(leftRect.height(), rightRect.height()) + pageSpacing;
2623
 
        }
2624
 
 
2625
 
        if(m_numberOfPages % 2 != 0)
2626
 
        {
2627
 
            PageItem* leftPageItem = m_pagesByIndex.at(m_numberOfPages - 1);
2628
 
            QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect());
2629
 
 
2630
 
            leftPageItem->setPos(pageSpacing - leftRect.left(), sceneHeight - leftRect.top());
2631
 
            m_pagesByHeight.insert(sceneHeight, leftPageItem);
2632
 
 
2633
 
            sceneWidth = qMax(sceneWidth, leftRect.width() + 2 * pageSpacing);
2634
 
            sceneHeight += leftRect.height() + pageSpacing;
2635
 
        }
2636
 
 
2637
 
        break;
2638
 
    }
2639
 
 
2640
 
    m_scene->setSceneRect(0.0, 0.0, sceneWidth, sceneHeight);
2641
 
    m_view->setSceneRect(0.0, 0.0, sceneWidth, sceneHeight);
2642
 
 
2643
 
    connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
2644
 
}
2645
 
 
2646
 
void DocumentView::prepareView(qreal top)
2647
 
{
2648
 
    disconnect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
2649
 
 
2650
 
    PageItem* leftPageItem = m_pagesByIndex.value(m_currentPage - 1, 0);
2651
 
    PageItem* rightPageItem = m_pagesByIndex.value(m_currentPage, 0);
2652
 
 
2653
 
    switch(m_pageLayout)
2654
 
    {
2655
 
    case OnePage:
2656
 
        foreach(PageItem* pageItem, m_pagesByIndex)
2657
 
        {
2658
 
            pageItem->setVisible(false);
2659
 
        }
2660
 
 
2661
 
        if(leftPageItem != 0)
2662
 
        {
2663
 
            leftPageItem->setVisible(true);
2664
 
 
2665
 
            QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect()).translated(leftPageItem->pos());
2666
 
 
2667
 
            m_view->setSceneRect(leftRect.adjusted(-pageSpacing, -pageSpacing, pageSpacing, pageSpacing));
2668
 
            m_view->verticalScrollBar()->setValue(qFloor(leftRect.top() + leftRect.height() * top));
2669
 
        }
2670
 
 
2671
 
        break;
2672
 
    case TwoPages:
2673
 
        foreach(PageItem* pageItem, m_pagesByIndex)
2674
 
        {
2675
 
            pageItem->setVisible(false);
2676
 
        }
2677
 
 
2678
 
        if(leftPageItem != 0 && rightPageItem != 0)
2679
 
        {
2680
 
            leftPageItem->setVisible(true);
2681
 
            rightPageItem->setVisible(true);
2682
 
 
2683
 
            QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect()).translated(leftPageItem->pos());
2684
 
            QRectF rightRect = m_pageTransform.mapRect(rightPageItem->boundingRect()).translated(rightPageItem->pos());
2685
 
 
2686
 
            m_view->setSceneRect(leftRect.united(rightRect).adjusted(-pageSpacing, -pageSpacing, pageSpacing, pageSpacing));
2687
 
            m_view->verticalScrollBar()->setValue(qFloor(leftRect.top() + leftRect.height() * top));
2688
 
        }
2689
 
        else if(leftPageItem != 0)
2690
 
        {
2691
 
            leftPageItem->setVisible(true);
2692
 
 
2693
 
            QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect()).translated(leftPageItem->pos());
2694
 
 
2695
 
            m_view->setSceneRect(leftRect.adjusted(-pageSpacing, -pageSpacing, pageSpacing, pageSpacing));
2696
 
            m_view->verticalScrollBar()->setValue(qFloor(leftRect.top() + leftRect.height() * top));
2697
 
        }
2698
 
 
2699
 
        break;
2700
 
    case OneColumn:
2701
 
    case TwoColumns:
2702
 
        foreach(PageItem* pageItem, m_pagesByIndex)
2703
 
        {
2704
 
            pageItem->setVisible(true);
2705
 
        }
2706
 
 
2707
 
        if(leftPageItem != 0)
2708
 
        {
2709
 
            QRectF leftRect = m_pageTransform.mapRect(leftPageItem->boundingRect()).translated(leftPageItem->pos());
2710
 
 
2711
 
            m_view->verticalScrollBar()->setValue(qFloor(leftRect.top() + leftRect.height() * top));
2712
 
        }
2713
 
 
2714
 
        break;
2715
 
    }
2716
 
 
2717
 
    m_view->update();
2718
 
 
2719
 
    connect(m_view->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(slotVerticalScrollBarValueChanged(int)));
2720
 
 
2721
 
    // highlight
2722
 
 
2723
 
    if(m_currentResult != m_results.end())
2724
 
    {
2725
 
        PageItem* pageItem = m_pagesByIndex.value(m_currentResult.key(), 0);
2726
 
 
2727
 
        if(pageItem != 0)
2728
 
        {
2729
 
            m_highlight->setPos(pageItem->pos());
2730
 
            m_highlight->setTransform(pageItem->m_highlightTransform);
2731
 
            m_highlight->setTransform(m_pageTransform, true);
2732
 
 
2733
 
            m_highlight->setRect(m_currentResult.value().adjusted(-1.0, -1.0, 1.0, 1.0));
2734
 
 
2735
 
            pageItem->stackBefore(m_highlight);
2736
 
 
2737
 
            m_highlight->setVisible(true);
2738
 
        }
2739
 
        else
2740
 
        {
2741
 
            m_highlight->setVisible(false);
2742
 
        }
2743
 
    }
2744
 
    else
2745
 
    {
2746
 
        m_highlight->setVisible(false);
2747
 
    }
2748
 
}