~adamreichold/qpdfview/trunk

« back to all changes in this revision

Viewing changes to 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
qreal DocumentView::s_pageSpacing = 5.0;
 
25
qreal DocumentView::s_thumbnailSpacing = 3.0;
 
26
 
 
27
qreal DocumentView::s_thumbnailSize = 150.0;
 
28
 
 
29
qreal DocumentView::s_minimumScaleFactor = 0.1;
 
30
qreal DocumentView::s_maximumScaleFactor = 10.0;
 
31
 
 
32
qreal DocumentView::pageSpacing()
 
33
{
 
34
    return s_pageSpacing;
 
35
}
 
36
 
 
37
void DocumentView::setPageSpacing(qreal pageSpacing)
 
38
{
 
39
    if(pageSpacing >= 0.0)
 
40
    {
 
41
        s_pageSpacing = pageSpacing;
 
42
    }
 
43
}
 
44
 
 
45
qreal DocumentView::thumbnailSpacing()
 
46
{
 
47
    return s_thumbnailSpacing;
 
48
}
 
49
 
 
50
void DocumentView::setThumbnailSpacing(qreal thumbnailSpacing)
 
51
{
 
52
    if(thumbnailSpacing >= 0.0)
 
53
    {
 
54
        s_thumbnailSpacing = thumbnailSpacing;
 
55
    }
 
56
}
 
57
 
 
58
qreal DocumentView::thumbnailSize()
 
59
{
 
60
    return s_thumbnailSize;
 
61
}
 
62
 
 
63
void DocumentView::setThumbnailSize(qreal thumbnailSize)
 
64
{
 
65
    if(thumbnailSize >= 0.0)
 
66
    {
 
67
        s_thumbnailSize = thumbnailSize;
 
68
    }
 
69
}
 
70
 
 
71
qreal DocumentView::minimumScaleFactor()
 
72
{
 
73
    return s_minimumScaleFactor;
 
74
}
 
75
 
 
76
qreal DocumentView::maximumScaleFactor()
 
77
{
 
78
    return s_maximumScaleFactor;
 
79
}
 
80
 
 
81
DocumentView::DocumentView(QWidget* parent) : QGraphicsView(parent),
 
82
    m_settings(0),
 
83
    m_mutex(),
 
84
    m_document(0),
 
85
    m_filePath(),
 
86
    m_numberOfPages(-1),
 
87
    m_currentPage(-1),
 
88
    m_returnToPage(-1),
 
89
    m_continuousMode(false),
 
90
    m_twoPagesMode(false),
 
91
    m_scaleMode(ScaleFactor),
 
92
    m_scaleFactor(1.0),
 
93
    m_rotation(Poppler::Page::Rotate0),
 
94
    m_highlightAll(false),
 
95
    m_pagesScene(0),
 
96
    m_pages(),
 
97
    m_heightToIndex(),
 
98
    m_thumbnailsScene(0),
 
99
    m_thumbnails(),
 
100
    m_highlight(0),
 
101
    m_outlineModel(0),
 
102
    m_propertiesModel(0),
 
103
    m_results(),
 
104
    m_currentResult(m_results.end()),
 
105
    m_search(0)
 
106
{
 
107
    m_pagesScene = new QGraphicsScene(this);
 
108
    m_thumbnailsScene = new QGraphicsScene(this);
 
109
 
 
110
    m_outlineModel = new QStandardItemModel(this);
 
111
    m_propertiesModel = new QStandardItemModel(this);
 
112
 
 
113
    setScene(m_pagesScene);
 
114
 
 
115
    setDragMode(QGraphicsView::ScrollHandDrag);
 
116
    setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
 
117
 
 
118
    setAcceptDrops(false);
 
119
 
 
120
    connect(verticalScrollBar(), SIGNAL(valueChanged(int)), SLOT(on_verticalScrollBar_valueChanged(int)));
 
121
 
 
122
    // highlight
 
123
 
 
124
    m_highlight = new QGraphicsRectItem();
 
125
 
 
126
    m_highlight->setVisible(false);
 
127
    scene()->addItem(m_highlight);
 
128
 
 
129
    QColor highlightColor = QApplication::palette().color(QPalette::Highlight);
 
130
 
 
131
    highlightColor.setAlpha(192);
 
132
    m_highlight->setBrush(QBrush(highlightColor));
 
133
 
 
134
    highlightColor.setAlpha(255);
 
135
    m_highlight->setPen(QPen(highlightColor));
 
136
 
 
137
    // search
 
138
 
 
139
    m_search = new QFutureWatcher< QPair< int, QList< QRectF > > >(this);
 
140
 
 
141
    connect(m_search, SIGNAL(resultReadyAt(int)), SLOT(on_search_resultReadyAt(int)));
 
142
    connect(m_search, SIGNAL(progressValueChanged(int)), SLOT(on_search_progressValueChanged(int)));
 
143
    connect(m_search, SIGNAL(canceled()), SIGNAL(searchCanceled()));
 
144
    connect(m_search, SIGNAL(finished()), SIGNAL(searchFinished()));
 
145
 
 
146
    // auto-refresh
 
147
 
 
148
    m_autoRefreshWatcher = new QFileSystemWatcher(this);
 
149
    m_autoRefreshTimer = new QTimer(this);
 
150
 
 
151
    m_autoRefreshTimer->setInterval(500);
 
152
    m_autoRefreshTimer->setSingleShot(true);
 
153
 
 
154
    connect(m_autoRefreshWatcher, SIGNAL(fileChanged(QString)), m_autoRefreshTimer, SLOT(start()));
 
155
    connect(m_autoRefreshTimer, SIGNAL(timeout()), this, SLOT(refresh()));
 
156
 
 
157
    // settings
 
158
 
 
159
    m_settings = new QSettings(this);
 
160
 
 
161
    m_continuousMode = m_settings->value("documentView/continuousMode", false).toBool();
 
162
    m_twoPagesMode = m_settings->value("documentView/twoPagesMode", false).toBool();
 
163
    m_scaleMode = static_cast< ScaleMode >(m_settings->value("documentView/scaleMode", 0).toUInt());
 
164
    m_scaleFactor = m_settings->value("documentView/scaleFactor", 1.0).toReal();
 
165
    m_rotation = static_cast< Poppler::Page::Rotation >(m_settings->value("documentView/rotation", 0).toUInt());
 
166
}
 
167
 
 
168
DocumentView::~DocumentView()
 
169
{
 
170
    qDeleteAll(m_pages);
 
171
    qDeleteAll(m_thumbnails);
 
172
 
 
173
    m_search->cancel();
 
174
    m_search->waitForFinished();
 
175
 
 
176
    if(m_document != 0)
 
177
    {
 
178
        delete m_document;
 
179
    }
 
180
 
 
181
    // settings
 
182
 
 
183
    m_settings->setValue("documentView/continuousMode", m_continuousMode);
 
184
    m_settings->setValue("documentView/twoPagesMode", m_twoPagesMode);
 
185
    m_settings->setValue("documentView/scaleMode", static_cast< uint >(m_scaleMode));
 
186
    m_settings->setValue("documentView/scaleFactor", m_scaleFactor);
 
187
    m_settings->setValue("documentView/rotation", static_cast< uint >(m_rotation));
 
188
}
 
189
 
 
190
const QString& DocumentView::filePath() const
 
191
{
 
192
    return m_filePath;
 
193
}
 
194
 
 
195
int DocumentView::numberOfPages() const
 
196
{
 
197
    return m_numberOfPages;
 
198
}
 
199
 
 
200
int DocumentView::currentPage() const
 
201
{
 
202
    return m_currentPage;
 
203
}
 
204
 
 
205
bool DocumentView::continousMode() const
 
206
{
 
207
    return m_continuousMode;
 
208
}
 
209
 
 
210
void DocumentView::setContinousMode(bool continousMode)
 
211
{
 
212
    if(m_continuousMode != continousMode)
 
213
    {
 
214
        m_continuousMode = continousMode;
 
215
 
 
216
        prepareView();
 
217
 
 
218
        emit continousModeChanged(m_continuousMode);
 
219
    }
 
220
}
 
221
 
 
222
bool DocumentView::twoPagesMode() const
 
223
{
 
224
    return m_twoPagesMode;
 
225
}
 
226
 
 
227
void DocumentView::setTwoPagesMode(bool twoPagesMode)
 
228
{
 
229
    if(m_twoPagesMode != twoPagesMode)
 
230
    {
 
231
        m_twoPagesMode = twoPagesMode;
 
232
 
 
233
        if(m_twoPagesMode)
 
234
        {
 
235
            if(m_currentPage != (m_currentPage % 2 != 0 ? m_currentPage :  m_currentPage - 1))
 
236
            {
 
237
                m_currentPage = m_currentPage % 2 != 0 ? m_currentPage :  m_currentPage - 1;
 
238
 
 
239
                emit currentPageChanged(m_currentPage);
 
240
            }
 
241
        }
 
242
 
 
243
        prepareScene();
 
244
        prepareView();
 
245
 
 
246
        emit twoPagesModeChanged(m_twoPagesMode);
 
247
    }
 
248
}
 
249
 
 
250
DocumentView::ScaleMode DocumentView::scaleMode() const
 
251
{
 
252
    return m_scaleMode;
 
253
}
 
254
 
 
255
void DocumentView::setScaleMode(ScaleMode scaleMode)
 
256
{
 
257
    if(m_scaleMode != scaleMode)
 
258
    {
 
259
        m_scaleMode = scaleMode;
 
260
 
 
261
        prepareScene();
 
262
        prepareView();
 
263
 
 
264
        emit scaleModeChanged(m_scaleMode);
 
265
    }
 
266
}
 
267
 
 
268
qreal DocumentView::scaleFactor() const
 
269
{
 
270
    return m_scaleFactor;
 
271
}
 
272
 
 
273
void DocumentView::setScaleFactor(qreal scaleFactor)
 
274
{
 
275
    if(m_scaleFactor != scaleFactor && scaleFactor >= s_minimumScaleFactor && scaleFactor <= s_maximumScaleFactor)
 
276
    {
 
277
        m_scaleFactor = scaleFactor;
 
278
 
 
279
        if(m_scaleMode == ScaleFactor)
 
280
        {
 
281
            prepareScene();
 
282
            prepareView();
 
283
        }
 
284
 
 
285
        emit scaleFactorChanged(m_scaleFactor);
 
286
    }
 
287
}
 
288
 
 
289
Poppler::Page::Rotation DocumentView::rotation() const
 
290
{
 
291
    return m_rotation;
 
292
}
 
293
 
 
294
void DocumentView::setRotation(Poppler::Page::Rotation rotation)
 
295
{
 
296
    if(m_rotation != rotation)
 
297
    {
 
298
        m_rotation = rotation;
 
299
 
 
300
        prepareScene();
 
301
        prepareView();
 
302
 
 
303
        emit rotationChanged(m_rotation);
 
304
    }
 
305
}
 
306
 
 
307
bool DocumentView::highlightAll() const
 
308
{
 
309
    return m_highlightAll;
 
310
}
 
311
 
 
312
void DocumentView::setHighlightAll(bool highlightAll)
 
313
{
 
314
    if(m_highlightAll != highlightAll)
 
315
    {
 
316
        m_highlightAll = highlightAll;
 
317
 
 
318
        for(int index = 0; index < m_numberOfPages; index++)
 
319
        {
 
320
            PageItem* page = m_pages.at(index);
 
321
 
 
322
            page->setHighlights(m_highlightAll ? m_results.values(index) : QList< QRectF >());
 
323
        }
 
324
 
 
325
        emit highlightAllChanged(m_highlightAll);
 
326
    }
 
327
}
 
328
 
 
329
QStandardItemModel* DocumentView::outlineModel() const
 
330
{
 
331
    return m_outlineModel;
 
332
}
 
333
 
 
334
QStandardItemModel* DocumentView::propertiesModel() const
 
335
{
 
336
    return m_propertiesModel;
 
337
}
 
338
 
 
339
QStandardItemModel* DocumentView::fontsModel()
 
340
{
 
341
    m_mutex.lock();
 
342
 
 
343
    QList< Poppler::FontInfo > fonts = m_document->fonts();
 
344
 
 
345
    m_mutex.unlock();
 
346
 
 
347
    QStandardItemModel* fontsModel = new QStandardItemModel();
 
348
 
 
349
    fontsModel->setRowCount(fonts.count());
 
350
    fontsModel->setColumnCount(5);
 
351
 
 
352
    fontsModel->setHorizontalHeaderLabels(QStringList() << tr("Name") << tr("Type") << tr("Embedded") << tr("Subset") << tr("File"));
 
353
 
 
354
    for(int index = 0; index < fonts.count(); index++)
 
355
    {
 
356
        Poppler::FontInfo font = fonts.at(index);
 
357
 
 
358
        fontsModel->setItem(index, 0, new QStandardItem(font.name()));
 
359
        fontsModel->setItem(index, 1, new QStandardItem(font.typeName()));
 
360
        fontsModel->setItem(index, 2, new QStandardItem(font.isEmbedded() ? tr("Yes") : tr("No")));
 
361
        fontsModel->setItem(index, 3, new QStandardItem(font.isSubset() ? tr("Yes") : tr("No")));
 
362
        fontsModel->setItem(index, 4, new QStandardItem(font.file()));
 
363
    }
 
364
 
 
365
    return fontsModel;
 
366
}
 
367
 
 
368
QGraphicsScene* DocumentView::thumbnailsScene() const
 
369
{
 
370
    return m_thumbnailsScene;
 
371
}
 
372
 
 
373
QGraphicsItem* DocumentView::thumbnailsItem(int page) const
 
374
{
 
375
    return m_thumbnails.value(page - 1, 0);
 
376
}
 
377
 
 
378
bool DocumentView::open(const QString& filePath)
 
379
{
 
380
    Poppler::Document* document = Poppler::Document::load(filePath);
 
381
 
 
382
    if(document != 0)
 
383
    {
 
384
        if(document->isLocked())
 
385
        {
 
386
            QString password = QInputDialog::getText(this, tr("Unlock document"), tr("Password:"), QLineEdit::Password);
 
387
 
 
388
            if(document->unlock(password.toLatin1(), password.toLatin1()))
 
389
            {
 
390
                delete document;
 
391
                return false;
 
392
            }
 
393
        }
 
394
 
 
395
        m_filePath = filePath;
 
396
        m_numberOfPages = document->numPages();
 
397
        m_currentPage = 1;
 
398
        m_returnToPage = -1;
 
399
 
 
400
        prepareDocument(document);
 
401
 
 
402
        emit filePathChanged(m_filePath);
 
403
        emit numberOfPagesChanged(m_numberOfPages);
 
404
        emit currentPageChanged(m_currentPage);
 
405
    }
 
406
 
 
407
    return document != 0;
 
408
}
 
409
 
 
410
bool DocumentView::refresh()
 
411
{
 
412
    Poppler::Document* document = Poppler::Document::load(m_filePath);
 
413
 
 
414
    if(document != 0)
 
415
    {
 
416
        if(document->isLocked())
 
417
        {
 
418
            QString password = QInputDialog::getText(this, tr("Unlock document"), tr("Password:"), QLineEdit::Password);
 
419
 
 
420
            if(document->unlock(password.toLatin1(), password.toLatin1()))
 
421
            {
 
422
                delete document;
 
423
                return false;
 
424
            }
 
425
        }
 
426
 
 
427
        m_numberOfPages = document->numPages();
 
428
        m_currentPage = m_currentPage <= m_numberOfPages ? m_currentPage : 1;
 
429
        m_returnToPage = m_returnToPage <= m_numberOfPages ? m_returnToPage : -1;
 
430
 
 
431
        prepareDocument(document);
 
432
 
 
433
        emit numberOfPagesChanged(m_numberOfPages);
 
434
        emit currentPageChanged(m_currentPage);
 
435
    }
 
436
 
 
437
    return document != 0;
 
438
}
 
439
 
 
440
bool DocumentView::saveCopy(const QString& filePath)
 
441
{
 
442
    m_mutex.lock();
 
443
 
 
444
    Poppler::PDFConverter* pdfConverter = m_document->pdfConverter();
 
445
 
 
446
    pdfConverter->setOutputFileName(filePath);
 
447
    bool ok = pdfConverter->convert();
 
448
 
 
449
    delete pdfConverter;
 
450
 
 
451
    m_mutex.unlock();
 
452
 
 
453
    return ok;
 
454
}
 
455
 
 
456
bool DocumentView::print(QPrinter* printer)
 
457
{
 
458
    int fromPage = printer->fromPage() != 0 ? printer->fromPage() : 1;
 
459
    int toPage = printer->toPage() != 0 ? printer->toPage() : m_numberOfPages;
 
460
 
 
461
#ifdef WITH_CUPS
 
462
 
 
463
    int num_dests = 0;
 
464
    cups_dest_t* dests = 0;
 
465
 
 
466
    int num_options = 0;
 
467
    cups_option_t* options = 0;
 
468
 
 
469
    cups_dest_t* dest = 0;
 
470
    int jobId = 0;
 
471
 
 
472
    num_dests = cupsGetDests(&dests);
 
473
 
 
474
    dest = cupsGetDest(printer->printerName().toLocal8Bit(), 0, num_dests, dests);
 
475
 
 
476
    if(dest != 0)
 
477
    {
 
478
        for(int index = 0; index < dest->num_options; index++)
 
479
        {
 
480
            num_options = cupsAddOption(dest->options[index].name, dest->options[index].value, num_options, &options);
 
481
        }
 
482
 
 
483
        num_options = cupsAddOption("page-ranges", QString("%1-%2").arg(fromPage).arg(toPage).toLocal8Bit(), num_options, &options);
 
484
 
 
485
        num_options = cupsAddOption("copies", QString("%1").arg(printer->copyCount()).toLocal8Bit(), num_options, &options);
 
486
 
 
487
        num_options = cupsAddOption("collate", QString("%1").arg(printer->collateCopies()).toLocal8Bit(), num_options, &options);
 
488
 
 
489
        switch(printer->duplex())
 
490
        {
 
491
        case QPrinter::DuplexNone:
 
492
            num_options = cupsAddOption("sides", "one-sided", num_options, &options);
 
493
            break;
 
494
        case QPrinter::DuplexAuto:
 
495
            break;
 
496
        case QPrinter::DuplexLongSide:
 
497
            num_options = cupsAddOption("sides", "two-sided-long-edge", num_options, &options);
 
498
            break;
 
499
        case QPrinter::DuplexShortSide:
 
500
            num_options = cupsAddOption("sides", "two-sided-short-edge", num_options, &options);
 
501
            break;
 
502
        }
 
503
 
 
504
        switch(printer->pageOrder())
 
505
        {
 
506
        case QPrinter::FirstPageFirst:
 
507
            num_options = cupsAddOption("outputorder", "normal", num_options, &options);
 
508
            break;
 
509
        case QPrinter::LastPageFirst:
 
510
            num_options = cupsAddOption("outputorder", "reverse", num_options, &options);
 
511
            break;
 
512
        }
 
513
 
 
514
        switch(printer->colorMode())
 
515
        {
 
516
        case QPrinter::Color:
 
517
            break;
 
518
        case QPrinter::GrayScale:
 
519
            num_options = cupsAddOption("ColorModel", "Gray", num_options, &options);
 
520
            break;
 
521
        }
 
522
 
 
523
        QFileInfo fileInfo(m_filePath);
 
524
 
 
525
        jobId = cupsPrintFile(dest->name, fileInfo.absoluteFilePath().toLocal8Bit(), fileInfo.completeBaseName().toLocal8Bit(), num_options, options);
 
526
 
 
527
        if(jobId < 1)
 
528
        {
 
529
            qDebug() << cupsLastErrorString();
 
530
        }
 
531
    }
 
532
    else
 
533
    {
 
534
        qDebug() << cupsLastErrorString();
 
535
    }
 
536
 
 
537
    cupsFreeDests(num_dests, dests);
 
538
    cupsFreeOptions(num_options, options);
 
539
 
 
540
    return jobId >= 1;
 
541
 
 
542
#else
 
543
 
 
544
    QProgressDialog* progressDialog = new QProgressDialog(this);
 
545
    progressDialog->setLabelText(tr("Printing '%1'...").arg(m_filePath));
 
546
    progressDialog->setRange(fromPage - 1, toPage);
 
547
 
 
548
    QPainter painter;
 
549
    painter.begin(printer);
 
550
 
 
551
    for(int index = fromPage - 1; index <= toPage - 1; index++)
 
552
    {
 
553
        progressDialog->setValue(index);
 
554
 
 
555
        QApplication::processEvents();
 
556
 
 
557
        {
 
558
            m_mutex.lock();
 
559
 
 
560
            Poppler::Page* page = m_document->page(index);
 
561
 
 
562
            qreal pageWidth =  printer->physicalDpiX() / 72.0 * page->pageSizeF().width();
 
563
            qreal pageHeight = printer->physicalDpiY() / 72.0 * page->pageSizeF().height();
 
564
 
 
565
            QImage image = page->renderToImage(printer->physicalDpiX(), printer->physicalDpiY());
 
566
 
 
567
            delete page;
 
568
 
 
569
            m_mutex.unlock();
 
570
 
 
571
            qreal scaleFactor = qMin(printer->width() / pageWidth, printer->height() / pageHeight);
 
572
 
 
573
            painter.setTransform(QTransform::fromScale(scaleFactor, scaleFactor));
 
574
            painter.drawImage(QPointF(), image);
 
575
        }
 
576
 
 
577
        if(index < toPage - 1)
 
578
        {
 
579
            printer->newPage();
 
580
        }
 
581
 
 
582
        QApplication::processEvents();
 
583
 
 
584
        if(progressDialog->wasCanceled())
 
585
        {
 
586
            delete progressDialog;
 
587
            return false;
 
588
        }
 
589
    }
 
590
 
 
591
    painter.end();
 
592
 
 
593
    delete progressDialog;
 
594
    return true;
 
595
 
 
596
#endif // WITH_CUPS
 
597
}
 
598
 
 
599
void DocumentView::previousPage()
 
600
{
 
601
    jumpToPage(currentPage() - (m_twoPagesMode ? 2 : 1));
 
602
}
 
603
 
 
604
void DocumentView::nextPage()
 
605
{
 
606
    jumpToPage(currentPage() + (m_twoPagesMode ? 2 : 1));
 
607
}
 
608
 
 
609
void DocumentView::firstPage()
 
610
{
 
611
    jumpToPage(1);
 
612
}
 
613
 
 
614
void DocumentView::lastPage()
 
615
{
 
616
    jumpToPage(numberOfPages());
 
617
}
 
618
 
 
619
void DocumentView::jumpToPage(int page, qreal changeLeft, qreal changeTop)
 
620
{
 
621
    if(page >= 1 && page <= m_numberOfPages && changeLeft >= 0.0 && changeLeft <= 1.0 && changeTop >= 0.0 && changeTop <= 1.0)
 
622
    {
 
623
        if(m_twoPagesMode)
 
624
        {
 
625
            if(m_currentPage != (page % 2 != 0 ? page : page - 1) || changeLeft != 0.0 || changeTop != 0.0)
 
626
            {
 
627
                m_returnToPage = m_currentPage;
 
628
                m_currentPage = page % 2 != 0 ? page : page - 1;
 
629
 
 
630
                prepareView(changeLeft, changeTop);
 
631
 
 
632
                emit currentPageChanged(m_currentPage);
 
633
            }
 
634
        }
 
635
        else
 
636
        {
 
637
            if(m_currentPage != page || changeLeft != 0.0 || changeTop != 0.0)
 
638
            {
 
639
                m_returnToPage = m_currentPage;
 
640
                m_currentPage = page;
 
641
 
 
642
                prepareView(changeLeft, changeTop);
 
643
 
 
644
                emit currentPageChanged(m_currentPage);
 
645
            }
 
646
        }
 
647
    }
 
648
}
 
649
 
 
650
void DocumentView::startSearch(const QString& text, bool matchCase)
 
651
{
 
652
    cancelSearch();
 
653
 
 
654
    QList< int > indices;
 
655
 
 
656
    indices.reserve(m_numberOfPages);
 
657
 
 
658
    for(int index = m_currentPage - 1; index < m_numberOfPages; index++)
 
659
    {
 
660
        indices.append(index);
 
661
    }
 
662
 
 
663
    for(int index = 0; index < m_currentPage - 1; index++)
 
664
    {
 
665
        indices.append(index);
 
666
    }
 
667
 
 
668
    m_search->setFuture(QtConcurrent::mapped(indices, Search(&m_mutex, m_document, text, matchCase)));
 
669
}
 
670
 
 
671
void DocumentView::cancelSearch()
 
672
{
 
673
    m_search->cancel();
 
674
    m_search->waitForFinished();
 
675
 
 
676
    m_results.clear();
 
677
    m_currentResult = m_results.end();
 
678
 
 
679
    if(m_highlightAll)
 
680
    {
 
681
        for(int index = 0; index < m_numberOfPages; index++)
 
682
        {
 
683
            PageItem* page = m_pages.at(index);
 
684
 
 
685
            page->setHighlights(QList< QRectF >());
 
686
        }
 
687
    }
 
688
 
 
689
    prepareHighlight();
 
690
}
 
691
 
 
692
void DocumentView::findPrevious()
 
693
{
 
694
    if(m_currentResult != m_results.end())
 
695
    {
 
696
        if(m_currentResult.key() == m_currentPage - 1 || (m_twoPagesMode && m_currentResult.key() == m_currentPage))
 
697
        {
 
698
            --m_currentResult;
 
699
        }
 
700
        else
 
701
        {
 
702
            m_currentResult = --m_results.upperBound(m_currentPage - 1);
 
703
        }
 
704
    }
 
705
    else
 
706
    {
 
707
        m_currentResult = --m_results.upperBound(m_currentPage - 1);
 
708
    }
 
709
 
 
710
    if(m_currentResult == m_results.end())
 
711
    {
 
712
        m_currentResult = --m_results.upperBound(m_numberOfPages - 1);
 
713
    }
 
714
 
 
715
    prepareHighlight();
 
716
}
 
717
 
 
718
void DocumentView::findNext()
 
719
{
 
720
    if(m_currentResult != m_results.end())
 
721
    {
 
722
        if(m_currentResult.key() == m_currentPage - 1 || (m_twoPagesMode && m_currentResult.key() == m_currentPage))
 
723
        {
 
724
            ++m_currentResult;
 
725
        }
 
726
        else
 
727
        {
 
728
            m_currentResult = --m_results.upperBound(m_currentPage - 1);
 
729
        }
 
730
    }
 
731
    else
 
732
    {
 
733
        m_currentResult = --m_results.upperBound(m_currentPage - 1);
 
734
    }
 
735
 
 
736
    if(m_currentResult == m_results.end())
 
737
    {
 
738
        m_currentResult = m_results.lowerBound(0);
 
739
    }
 
740
 
 
741
    prepareHighlight();
 
742
}
 
743
 
 
744
void DocumentView::zoomIn()
 
745
{
 
746
    if(scaleMode() != ScaleFactor)
 
747
    {
 
748
        PageItem* page = m_pages.at(m_currentPage - 1);
 
749
 
 
750
        setScaleFactor(qMin(page->scaleFactor() + 0.1, s_maximumScaleFactor));
 
751
        setScaleMode(ScaleFactor);
 
752
    }
 
753
    else
 
754
    {
 
755
        setScaleFactor(qMin(scaleFactor() + 0.1, s_maximumScaleFactor));
 
756
    }
 
757
}
 
758
 
 
759
void DocumentView::zoomOut()
 
760
{
 
761
    if(scaleMode() != ScaleFactor)
 
762
    {
 
763
        PageItem* page = m_pages.at(m_currentPage - 1);
 
764
 
 
765
        setScaleFactor(qMax(page->scaleFactor() - 0.1, s_minimumScaleFactor));
 
766
        setScaleMode(ScaleFactor);
 
767
    }
 
768
    else
 
769
    {
 
770
        setScaleFactor(qMax(scaleFactor() - 0.1, s_minimumScaleFactor));
 
771
    }
 
772
}
 
773
 
 
774
void DocumentView::originalSize()
 
775
{
 
776
    setScaleFactor(1.0);
 
777
    setScaleMode(ScaleFactor);
 
778
}
 
779
 
 
780
void DocumentView::rotateLeft()
 
781
{
 
782
    switch(rotation())
 
783
    {
 
784
    case Poppler::Page::Rotate0:
 
785
        setRotation(Poppler::Page::Rotate270);
 
786
        break;
 
787
    case Poppler::Page::Rotate90:
 
788
        setRotation(Poppler::Page::Rotate0);
 
789
        break;
 
790
    case Poppler::Page::Rotate180:
 
791
        setRotation(Poppler::Page::Rotate90);
 
792
        break;
 
793
    case Poppler::Page::Rotate270:
 
794
        setRotation(Poppler::Page::Rotate180);
 
795
        break;
 
796
    }
 
797
}
 
798
 
 
799
void DocumentView::rotateRight()
 
800
{
 
801
    switch(rotation())
 
802
    {
 
803
    case Poppler::Page::Rotate0:
 
804
        setRotation(Poppler::Page::Rotate90);
 
805
        break;
 
806
    case Poppler::Page::Rotate90:
 
807
        setRotation(Poppler::Page::Rotate180);
 
808
        break;
 
809
    case Poppler::Page::Rotate180:
 
810
        setRotation(Poppler::Page::Rotate270);
 
811
        break;
 
812
    case Poppler::Page::Rotate270:
 
813
        setRotation(Poppler::Page::Rotate0);
 
814
        break;
 
815
    }
 
816
}
 
817
 
 
818
void DocumentView::presentation()
 
819
{
 
820
    PresentationView* presentationView = new PresentationView(&m_mutex, m_document);
 
821
 
 
822
    presentationView->jumpToPage(currentPage());
 
823
 
 
824
    presentationView->show();
 
825
    presentationView->setAttribute(Qt::WA_DeleteOnClose);
 
826
}
 
827
 
 
828
void DocumentView::on_verticalScrollBar_valueChanged(int value)
 
829
{
 
830
    if(m_continuousMode)
 
831
    {
 
832
        QMap< qreal, int >::const_iterator lowerBound = m_heightToIndex.lowerBound(-value);
 
833
 
 
834
        if(lowerBound != m_heightToIndex.end())
 
835
        {
 
836
            int page = lowerBound.value() + 1;
 
837
 
 
838
            if(m_currentPage != page)
 
839
            {
 
840
                m_currentPage = page;
 
841
 
 
842
                emit currentPageChanged(m_currentPage);
 
843
            }
 
844
        }
 
845
    }
 
846
}
 
847
 
 
848
void DocumentView::on_pages_linkClicked(int page, qreal left, qreal top)
 
849
{
 
850
    page = page >= 1 ? page : 1;
 
851
    page = page <= m_numberOfPages ? page : m_numberOfPages;
 
852
 
 
853
    left = left >= 0.0 ? left : 0.0;
 
854
    left = left <= 1.0 ? left : 1.0;
 
855
 
 
856
    top = top >= 0.0 ? top : 0.0;
 
857
    top = top <= 1.0 ? top : 1.0;
 
858
 
 
859
    jumpToPage(page, left, top);
 
860
}
 
861
 
 
862
void DocumentView::on_pages_linkClicked(const QString& url)
 
863
{
 
864
    if(m_settings->value("documentView/openUrl", false).toBool())
 
865
    {
 
866
        QDesktopServices::openUrl(QUrl(url));
 
867
    }
 
868
    else
 
869
    {
 
870
        QMessageBox::information(this, tr("Information"), tr("Opening URL is disabled in the settings."));
 
871
    }
 
872
}
 
873
 
 
874
void DocumentView::on_thumbnails_pageClicked(int page)
 
875
{
 
876
    page = page >= 1 ? page : 1;
 
877
    page = page <= m_numberOfPages ? page : m_numberOfPages;
 
878
 
 
879
    jumpToPage(page);
 
880
}
 
881
 
 
882
void DocumentView::on_search_resultReadyAt(int resultIndex)
 
883
{
 
884
    int pageIndex = m_search->resultAt(resultIndex).first;
 
885
    QList< QRectF > results = m_search->resultAt(resultIndex).second;
 
886
 
 
887
    for(int index = results.count() - 1; index >= 0; index--)
 
888
    {
 
889
        m_results.insertMulti(pageIndex, results.at(index));
 
890
    }
 
891
 
 
892
    if(m_highlightAll)
 
893
    {
 
894
        PageItem* page = m_pages.at(pageIndex);
 
895
 
 
896
        page->setHighlights(results);
 
897
    }
 
898
 
 
899
    if(pageIndex >= m_currentPage - 1 && !results.isEmpty() && m_currentResult == m_results.end())
 
900
    {
 
901
        findNext();
 
902
    }
 
903
}
 
904
 
 
905
void DocumentView::on_search_progressValueChanged(int progressValue)
 
906
{
 
907
    emit searchProgressed(100 * (progressValue - m_search->progressMinimum()) / (m_search->progressMaximum() - m_search->progressMinimum()));
 
908
}
 
909
 
 
910
void DocumentView::showEvent(QShowEvent* event)
 
911
{
 
912
    QGraphicsView::showEvent(event);
 
913
 
 
914
    if(!event->spontaneous())
 
915
    {
 
916
        prepareView();
 
917
    }
 
918
}
 
919
 
 
920
void DocumentView::resizeEvent(QResizeEvent* event)
 
921
{
 
922
    QGraphicsView::resizeEvent(event);
 
923
 
 
924
    if(m_scaleMode != ScaleFactor)
 
925
    {
 
926
        prepareScene();
 
927
        prepareView();
 
928
    }
 
929
}
 
930
 
 
931
void DocumentView::contextMenuEvent(QContextMenuEvent* event)
 
932
{
 
933
    QMenu* menu = new QMenu();
 
934
 
 
935
    QAction* returnAction = menu->addAction(tr("&Return"));
 
936
    returnAction->setShortcut(QKeySequence(Qt::Key_Return));
 
937
    returnAction->setEnabled(m_returnToPage != -1);
 
938
 
 
939
    QAction* action = menu->exec(event->globalPos());
 
940
 
 
941
    if(action == returnAction)
 
942
    {
 
943
        jumpToPage(m_returnToPage);
 
944
    }
 
945
 
 
946
    delete menu;
 
947
}
 
948
 
 
949
void DocumentView::keyPressEvent(QKeyEvent* event)
 
950
{
 
951
    if(event->modifiers() == Qt::NoModifier)
 
952
    {
 
953
        if(event->key() == Qt::Key_Return)
 
954
        {
 
955
            jumpToPage(m_returnToPage);
 
956
 
 
957
            event->accept();
 
958
            return;
 
959
        }
 
960
 
 
961
        if(!m_continuousMode)
 
962
        {
 
963
            if(event->key() == Qt::Key_PageUp && verticalScrollBar()->value() == verticalScrollBar()->minimum() && m_currentPage > 1)
 
964
            {
 
965
                previousPage();
 
966
 
 
967
                verticalScrollBar()->setValue(verticalScrollBar()->maximum());
 
968
 
 
969
                event->accept();
 
970
                return;
 
971
            }
 
972
            else if(event->key() == Qt::Key_PageDown && verticalScrollBar()->value() == verticalScrollBar()->maximum() && !currentPageIsLastPage())
 
973
            {
 
974
                nextPage();
 
975
 
 
976
                verticalScrollBar()->setValue(verticalScrollBar()->minimum());
 
977
 
 
978
                event->accept();
 
979
                return;
 
980
            }
 
981
        }
 
982
    }
 
983
 
 
984
    QGraphicsView::keyPressEvent(event);
 
985
}
 
986
 
 
987
void DocumentView::wheelEvent(QWheelEvent* event)
 
988
{
 
989
    if(event->modifiers() == Qt::ControlModifier)
 
990
    {
 
991
        if(event->delta() > 0)
 
992
        {
 
993
            zoomIn();
 
994
        }
 
995
        else
 
996
        {
 
997
            zoomOut();
 
998
        }
 
999
 
 
1000
        event->accept();
 
1001
        return;
 
1002
    }
 
1003
    else if(event->modifiers() == Qt::ShiftModifier)
 
1004
    {
 
1005
        if(event->delta() > 0)
 
1006
        {
 
1007
            rotateLeft();
 
1008
        }
 
1009
        else
 
1010
        {
 
1011
            rotateRight();
 
1012
        }
 
1013
 
 
1014
        event->accept();
 
1015
        return;
 
1016
    }
 
1017
    else if(event->modifiers() == Qt::NoModifier)
 
1018
    {
 
1019
        if(!m_continuousMode)
 
1020
        {
 
1021
            if(event->delta() > 0 && verticalScrollBar()->value() == verticalScrollBar()->minimum() && m_currentPage > 1)
 
1022
            {
 
1023
                previousPage();
 
1024
 
 
1025
                verticalScrollBar()->setValue(verticalScrollBar()->maximum());
 
1026
 
 
1027
                event->accept();
 
1028
                return;
 
1029
            }
 
1030
            else if(event->delta() < 0 && verticalScrollBar()->value() == verticalScrollBar()->maximum() && !currentPageIsLastPage())
 
1031
            {
 
1032
                nextPage();
 
1033
 
 
1034
                verticalScrollBar()->setValue(verticalScrollBar()->minimum());
 
1035
 
 
1036
                event->accept();
 
1037
                return;
 
1038
            }
 
1039
        }
 
1040
    }
 
1041
 
 
1042
    QGraphicsView::wheelEvent(event);
 
1043
}
 
1044
 
 
1045
bool DocumentView::currentPageIsLastPage()
 
1046
{
 
1047
    if(m_twoPagesMode)
 
1048
    {
 
1049
        return m_currentPage == (m_numberOfPages % 2 != 0 ? m_numberOfPages : m_numberOfPages - 1);
 
1050
    }
 
1051
    else
 
1052
    {
 
1053
        return m_currentPage == m_numberOfPages;
 
1054
    }
 
1055
}
 
1056
 
 
1057
void DocumentView::prepareDocument(Poppler::Document* document)
 
1058
{
 
1059
    qDeleteAll(m_pages);
 
1060
    qDeleteAll(m_thumbnails);
 
1061
 
 
1062
    cancelSearch();
 
1063
 
 
1064
    if(m_document != 0)
 
1065
    {
 
1066
        delete m_document;
 
1067
 
 
1068
        if(!m_autoRefreshWatcher->files().isEmpty())
 
1069
        {
 
1070
            m_autoRefreshWatcher->removePaths(m_autoRefreshWatcher->files());
 
1071
        }
 
1072
    }
 
1073
 
 
1074
    m_document = document;
 
1075
 
 
1076
    if(m_settings->value("documentView/autoRefresh", false).toBool())
 
1077
    {
 
1078
        m_autoRefreshWatcher->addPath(m_filePath);
 
1079
    }
 
1080
 
 
1081
    m_document->setRenderHint(Poppler::Document::Antialiasing, m_settings->value("documentView/antialiasing", true).toBool());
 
1082
    m_document->setRenderHint(Poppler::Document::TextAntialiasing, m_settings->value("documentView/textAntialiasing", true).toBool());
 
1083
    m_document->setRenderHint(Poppler::Document::TextHinting, m_settings->value("documentView/textHinting", false).toBool());
 
1084
 
 
1085
    preparePages();
 
1086
    prepareThumbnails();
 
1087
    prepareOutline();
 
1088
    prepareProperties();
 
1089
 
 
1090
    prepareScene();
 
1091
    prepareView();
 
1092
}
 
1093
 
 
1094
void DocumentView::preparePages()
 
1095
{
 
1096
    m_pages.clear();
 
1097
    m_pages.reserve(m_numberOfPages);
 
1098
 
 
1099
    for(int index = 0; index < m_numberOfPages; index++)
 
1100
    {
 
1101
        PageItem* page = new PageItem(&m_mutex, m_document, index);
 
1102
 
 
1103
        page->setPhysicalDpi(physicalDpiX(), physicalDpiY());
 
1104
 
 
1105
        m_pagesScene->addItem(page);
 
1106
        m_pages.append(page);
 
1107
 
 
1108
        connect(page, SIGNAL(linkClicked(int,qreal,qreal)), SLOT(on_pages_linkClicked(int,qreal,qreal)));
 
1109
        connect(page, SIGNAL(linkClicked(QString)), SLOT(on_pages_linkClicked(QString)));
 
1110
    }
 
1111
 
 
1112
    if(m_settings->value("pageItem/decoratePages", true).toBool())
 
1113
    {
 
1114
        m_pagesScene->setBackgroundBrush(QBrush(Qt::darkGray));
 
1115
    }
 
1116
    else
 
1117
    {
 
1118
        m_pagesScene->setBackgroundBrush(QBrush(Qt::white));
 
1119
    }
 
1120
}
 
1121
 
 
1122
void DocumentView::prepareThumbnails()
 
1123
{
 
1124
    m_thumbnails.clear();
 
1125
    m_thumbnails.reserve(m_numberOfPages);
 
1126
 
 
1127
    qreal left = 0.0;
 
1128
    qreal right = 0.0;
 
1129
    qreal height = s_thumbnailSpacing;
 
1130
 
 
1131
    for(int index = 0; index < m_numberOfPages; index++)
 
1132
    {
 
1133
        ThumbnailItem* page = new ThumbnailItem(&m_mutex, m_document, index);
 
1134
 
 
1135
        page->setPhysicalDpi(physicalDpiX(), physicalDpiY());
 
1136
 
 
1137
        m_thumbnailsScene->addItem(page);
 
1138
        m_thumbnails.append(page);
 
1139
 
 
1140
        connect(page, SIGNAL(pageClicked(int)), SLOT(on_thumbnails_pageClicked(int)));
 
1141
 
 
1142
        {
 
1143
            // prepare scale factor
 
1144
 
 
1145
            QSizeF size = page->size();
 
1146
 
 
1147
            qreal pageWidth = physicalDpiX() / 72.0 * size.width();
 
1148
            qreal pageHeight = physicalDpiY() / 72.0 * size.height();
 
1149
 
 
1150
            page->setScaleFactor(qMin(s_thumbnailSize / pageWidth, s_thumbnailSize / pageHeight));
 
1151
        }
 
1152
 
 
1153
        {
 
1154
            // prepare layout
 
1155
 
 
1156
            QRectF boundingRect = page->boundingRect();
 
1157
 
 
1158
            page->setPos(-boundingRect.left() - 0.5 * boundingRect.width(), height - boundingRect.top());
 
1159
 
 
1160
            left = qMin(left, -0.5 * boundingRect.width() - s_thumbnailSpacing);
 
1161
            right = qMax(right, 0.5 * boundingRect.width() + s_thumbnailSpacing);
 
1162
            height += boundingRect.height() + s_thumbnailSpacing;
 
1163
        }
 
1164
 
 
1165
        QGraphicsSimpleTextItem* text = m_thumbnailsScene->addSimpleText(QString::number(index + 1));
 
1166
 
 
1167
        text->setPos(-0.5 * text->boundingRect().width(), height);
 
1168
 
 
1169
        height += text->boundingRect().height() + s_thumbnailSpacing;
 
1170
    }
 
1171
 
 
1172
    if(m_settings->value("pageItem/decoratePages", true).toBool())
 
1173
    {
 
1174
        m_thumbnailsScene->setBackgroundBrush(QBrush(Qt::darkGray));
 
1175
    }
 
1176
    else
 
1177
    {
 
1178
        m_thumbnailsScene->setBackgroundBrush(QBrush(Qt::white));
 
1179
    }
 
1180
 
 
1181
    m_thumbnailsScene->setSceneRect(left, 0.0, right - left, height);
 
1182
}
 
1183
 
 
1184
void DocumentView::prepareOutline()
 
1185
{
 
1186
    m_outlineModel->clear();
 
1187
 
 
1188
    QDomDocument* toc = m_document->toc();
 
1189
 
 
1190
    if(toc != 0)
 
1191
    {
 
1192
        prepareOutline(toc->firstChild(), m_outlineModel->invisibleRootItem());
 
1193
 
 
1194
        delete toc;
 
1195
    }
 
1196
}
 
1197
 
 
1198
void DocumentView::prepareOutline(const QDomNode& node, QStandardItem* parent)
 
1199
{
 
1200
    QDomElement element = node.toElement();
 
1201
 
 
1202
    QStandardItem* item = new QStandardItem();
 
1203
 
 
1204
    item->setFlags(Qt::ItemIsEnabled);
 
1205
 
 
1206
    item->setText(element.tagName());
 
1207
    item->setToolTip(element.tagName());
 
1208
 
 
1209
    Poppler::LinkDestination* linkDestination = 0;
 
1210
 
 
1211
    if(element.hasAttribute("Destination"))
 
1212
    {
 
1213
        linkDestination = new Poppler::LinkDestination(element.attribute("Destination"));
 
1214
    }
 
1215
    else if(element.hasAttribute("DestinationName"))
 
1216
    {
 
1217
        linkDestination = m_document->linkDestination(element.attribute("DestinationName"));
 
1218
    }
 
1219
 
 
1220
    if(linkDestination != 0)
 
1221
    {
 
1222
        int page = linkDestination->pageNumber();
 
1223
        qreal left = 0.0;
 
1224
        qreal top = 0.0;
 
1225
 
 
1226
        page = page >= 1 ? page : 1;
 
1227
        page = page <= m_numberOfPages ? page : m_numberOfPages;
 
1228
 
 
1229
        if(linkDestination->isChangeLeft())
 
1230
        {
 
1231
            left = linkDestination->left();
 
1232
 
 
1233
            left = left >= 0.0 ? left : 0.0;
 
1234
            left = left <= 1.0 ? left : 1.0;
 
1235
        }
 
1236
 
 
1237
        if(linkDestination->isChangeTop())
 
1238
        {
 
1239
            top = linkDestination->top();
 
1240
 
 
1241
            top = top >= 0.0 ? top : 0.0;
 
1242
            top = top <= 1.0 ? top : 1.0;
 
1243
        }
 
1244
 
 
1245
        item->setData(page, Qt::UserRole + 1);
 
1246
        item->setData(left, Qt::UserRole + 2);
 
1247
        item->setData(top, Qt::UserRole + 3);
 
1248
 
 
1249
        delete linkDestination;
 
1250
    }
 
1251
 
 
1252
    parent->appendRow(item);
 
1253
 
 
1254
    QDomNode siblingNode = node.nextSibling();
 
1255
    if(!siblingNode.isNull())
 
1256
    {
 
1257
        prepareOutline(siblingNode, parent);
 
1258
    }
 
1259
 
 
1260
    QDomNode childNode = node.firstChild();
 
1261
    if(!childNode.isNull())
 
1262
    {
 
1263
        prepareOutline(childNode, item);
 
1264
    }
 
1265
}
 
1266
 
 
1267
void DocumentView::prepareProperties()
 
1268
{
 
1269
    m_propertiesModel->clear();
 
1270
 
 
1271
    QStringList keys = m_document->infoKeys();
 
1272
 
 
1273
    m_propertiesModel->setRowCount(keys.count());
 
1274
    m_propertiesModel->setColumnCount(2);
 
1275
 
 
1276
    for(int index = 0; index < keys.count(); index++)
 
1277
    {
 
1278
        QString key = keys.at(index);
 
1279
        QString value = m_document->info(key);
 
1280
 
 
1281
        if(value.startsWith("D:"))
 
1282
        {
 
1283
            value = m_document->date(key).toString();
 
1284
        }
 
1285
 
 
1286
        m_propertiesModel->setItem(index, 0, new QStandardItem(key));
 
1287
        m_propertiesModel->setItem(index, 1, new QStandardItem(value));
 
1288
    }
 
1289
}
 
1290
 
 
1291
void DocumentView::prepareScene()
 
1292
{
 
1293
    // prepare scale factor and rotation
 
1294
 
 
1295
    for(int index = 0; index < m_numberOfPages; index++)
 
1296
    {
 
1297
        PageItem* page = m_pages.at(index);
 
1298
        QSizeF size = page->size();
 
1299
 
 
1300
        if(m_scaleMode != ScaleFactor)
 
1301
        {
 
1302
            qreal visibleWidth = 0.0;
 
1303
            qreal visibleHeight = 0.0;
 
1304
 
 
1305
            qreal pageWidth = 0.0;
 
1306
            qreal pageHeight = 0.0;
 
1307
 
 
1308
            qreal scaleFactor = 1.0;
 
1309
 
 
1310
            if(m_twoPagesMode)
 
1311
            {
 
1312
                visibleWidth = 0.5 * (viewport()->width() - 6 - 3.0 * s_pageSpacing);
 
1313
            }
 
1314
            else
 
1315
            {
 
1316
                visibleWidth = viewport()->width() - 6 - 2.0 * s_pageSpacing;
 
1317
            }
 
1318
 
 
1319
            visibleHeight = viewport()->height() - 2.0 * s_pageSpacing;
 
1320
 
 
1321
            switch(m_rotation)
 
1322
            {
 
1323
            case Poppler::Page::Rotate0:
 
1324
            case Poppler::Page::Rotate180:
 
1325
                pageWidth = physicalDpiX() / 72.0 * size.width();
 
1326
                pageHeight = physicalDpiY() / 72.0 * size.height();
 
1327
                break;
 
1328
            case Poppler::Page::Rotate90:
 
1329
            case Poppler::Page::Rotate270:
 
1330
                pageWidth = physicalDpiX() / 72.0 * size.height();
 
1331
                pageHeight = physicalDpiY() / 72.0 * size.width();
 
1332
                break;
 
1333
            }
 
1334
 
 
1335
            switch(m_scaleMode)
 
1336
            {
 
1337
            case ScaleFactor:
 
1338
                break;
 
1339
            case FitToPageWidth:
 
1340
                scaleFactor = visibleWidth / pageWidth;
 
1341
                break;
 
1342
            case FitToPageSize:
 
1343
                scaleFactor = qMin(visibleWidth / pageWidth, visibleHeight / pageHeight);
 
1344
                break;
 
1345
            }
 
1346
 
 
1347
            page->setScaleFactor(scaleFactor);
 
1348
        }
 
1349
        else
 
1350
        {
 
1351
            page->setScaleFactor(m_scaleFactor);
 
1352
        }
 
1353
 
 
1354
        page->setRotation(m_rotation);
 
1355
    }
 
1356
 
 
1357
    // prepare layout
 
1358
 
 
1359
    m_heightToIndex.clear();
 
1360
 
 
1361
    qreal pageHeight = 0.0;
 
1362
 
 
1363
    qreal left = 0.0;
 
1364
    qreal right = 0.0;
 
1365
    qreal height = s_pageSpacing;
 
1366
 
 
1367
    for(int index = 0; index < m_numberOfPages; index++)
 
1368
    {
 
1369
        PageItem* page = m_pages.at(index);
 
1370
        QRectF boundingRect = page->boundingRect();
 
1371
 
 
1372
        if(m_twoPagesMode)
 
1373
        {
 
1374
            if(index % 2 == 0)
 
1375
            {
 
1376
                page->setPos(-boundingRect.left() - boundingRect.width() - 0.5 * s_pageSpacing, height - boundingRect.top());
 
1377
 
 
1378
                m_heightToIndex.insert(-height + s_pageSpacing + 0.3 * pageHeight, index);
 
1379
 
 
1380
                pageHeight = boundingRect.height();
 
1381
 
 
1382
                left = qMin(left, -boundingRect.width() - 1.5 * s_pageSpacing);
 
1383
            }
 
1384
            else
 
1385
            {
 
1386
                page->setPos(-boundingRect.left() + 0.5 * s_pageSpacing, height - boundingRect.top());
 
1387
 
 
1388
                pageHeight = qMax(pageHeight, boundingRect.height());
 
1389
 
 
1390
                right = qMax(right, boundingRect.width() + 1.5 * s_pageSpacing);
 
1391
                height += pageHeight + s_pageSpacing;
 
1392
            }
 
1393
        }
 
1394
        else
 
1395
        {
 
1396
            page->setPos(-boundingRect.left() - 0.5 * boundingRect.width(), height - boundingRect.top());
 
1397
 
 
1398
            m_heightToIndex.insert(-height + s_pageSpacing + 0.3 * pageHeight, index);
 
1399
 
 
1400
            pageHeight = boundingRect.height();
 
1401
 
 
1402
            left = qMin(left, -0.5 * boundingRect.width() - s_pageSpacing);
 
1403
            right = qMax(right, 0.5 * boundingRect.width() + s_pageSpacing);
 
1404
            height += pageHeight + s_pageSpacing;
 
1405
        }
 
1406
    }
 
1407
 
 
1408
    m_pagesScene->setSceneRect(left, 0.0, right - left, height);
 
1409
}
 
1410
 
 
1411
void DocumentView::prepareView(qreal changeLeft, qreal changeTop)
 
1412
{
 
1413
    qreal left = m_pagesScene->sceneRect().left();
 
1414
    qreal top = 0.0;
 
1415
    qreal width = m_pagesScene->sceneRect().width();
 
1416
    qreal height = m_pagesScene->sceneRect().height();
 
1417
 
 
1418
    int horizontalValue = 0;
 
1419
    int verticalValue = 0;
 
1420
 
 
1421
    for(int index = 0; index < m_pages.count(); index++)
 
1422
    {
 
1423
        PageItem* page = m_pages.at(index);
 
1424
 
 
1425
        if(m_continuousMode)
 
1426
        {
 
1427
            page->setVisible(true);
 
1428
 
 
1429
            if(Q_UNLIKELY(index == m_currentPage - 1))
 
1430
            {
 
1431
                QRectF boundingRect = page->boundingRect().translated(page->pos());
 
1432
 
 
1433
                horizontalValue = qFloor(boundingRect.left() + changeLeft * boundingRect.width());
 
1434
                verticalValue = qFloor(boundingRect.top() + changeTop * boundingRect.height());
 
1435
            }
 
1436
        }
 
1437
        else
 
1438
        {
 
1439
            if(Q_UNLIKELY(index == m_currentPage - 1))
 
1440
            {
 
1441
                page->setVisible(true);
 
1442
 
 
1443
                QRectF boundingRect = page->boundingRect().translated(page->pos());
 
1444
 
 
1445
                top = boundingRect.top() - s_pageSpacing;
 
1446
                height = boundingRect.height() + 2.0 * s_pageSpacing;
 
1447
 
 
1448
                horizontalValue = qFloor(boundingRect.left() + changeLeft * boundingRect.width());
 
1449
                verticalValue = qFloor(boundingRect.top() + changeTop * boundingRect.height());
 
1450
            }
 
1451
            else if(m_twoPagesMode && Q_UNLIKELY(index == m_currentPage))
 
1452
            {
 
1453
                page->setVisible(true);
 
1454
 
 
1455
                QRectF boundingRect = page->boundingRect().translated(page->pos());
 
1456
 
 
1457
                top = qMin(top, boundingRect.top() - s_pageSpacing);
 
1458
                height = qMax(height, boundingRect.height() + 2.0 * s_pageSpacing);
 
1459
            }
 
1460
            else
 
1461
            {
 
1462
                page->setVisible(false);
 
1463
            }
 
1464
        }
 
1465
 
 
1466
        if(m_currentResult != m_results.end())
 
1467
        {
 
1468
            if(Q_UNLIKELY(m_currentResult.key() == index))
 
1469
            {
 
1470
                m_highlight->setPos(page->pos());
 
1471
                m_highlight->setTransform(page->transform());
 
1472
                page->stackBefore(m_highlight);
 
1473
            }
 
1474
        }
 
1475
    }
 
1476
 
 
1477
    setSceneRect(left, top, width, height);
 
1478
 
 
1479
    horizontalScrollBar()->setValue(horizontalValue);
 
1480
    verticalScrollBar()->setValue(verticalValue);
 
1481
}
 
1482
 
 
1483
void DocumentView::prepareHighlight()
 
1484
{
 
1485
    if(m_currentResult != m_results.end())
 
1486
    {
 
1487
        jumpToPage(m_currentResult.key() + 1);
 
1488
 
 
1489
        PageItem* page = m_pages.at(m_currentResult.key());
 
1490
 
 
1491
        m_highlight->setPos(page->pos());
 
1492
        m_highlight->setTransform(page->transform());
 
1493
        page->stackBefore(m_highlight);
 
1494
 
 
1495
        m_highlight->setRect(m_currentResult.value());
 
1496
 
 
1497
        m_highlight->setVisible(true);
 
1498
 
 
1499
        disconnect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(on_verticalScrollBar_valueChanged(int)));
 
1500
        centerOn(m_highlight);
 
1501
        connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(on_verticalScrollBar_valueChanged(int)));
 
1502
    }
 
1503
    else
 
1504
    {
 
1505
        m_highlight->setVisible(false);
 
1506
    }
 
1507
}
 
1508
 
 
1509
DocumentView::Search::Search(QMutex *mutex, Poppler::Document *document, const QString &text, bool matchCase) :
 
1510
    m_mutex(mutex),
 
1511
    m_document(document),
 
1512
    m_text(text),
 
1513
    m_matchCase(matchCase)
 
1514
{
 
1515
}
 
1516
 
 
1517
QPair< int, QList< QRectF > > DocumentView::Search::operator()(int index)
 
1518
{
 
1519
    QList< QRectF > results;
 
1520
 
 
1521
    m_mutex->lock();
 
1522
 
 
1523
    Poppler::Page* page = m_document->page(index);
 
1524
 
 
1525
#if defined(HAS_POPPLER_22)
 
1526
 
 
1527
    results = page->search(m_text, m_matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive);
 
1528
 
 
1529
#elif defined(HAS_POPPLER_14)
 
1530
 
 
1531
    double left = 0.0, top = 0.0, right = 0.0, bottom = 0.0;
 
1532
 
 
1533
    while(page->search(m_text, left, top, right, bottom, Poppler::Page::NextResult, m_matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive))
 
1534
    {
 
1535
        QRectF rect;
 
1536
        rect.setLeft(left);
 
1537
        rect.setTop(top);
 
1538
        rect.setRight(right);
 
1539
        rect.setBottom(bottom);
 
1540
 
 
1541
        results.append(rect);
 
1542
    }
 
1543
 
 
1544
#else
 
1545
 
 
1546
    QRectF rect;
 
1547
 
 
1548
    while(page->search(m_text, rect, Poppler::Page::NextResult, m_matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive))
 
1549
    {
 
1550
        results.append(rect);
 
1551
    }
 
1552
 
 
1553
#endif
 
1554
 
 
1555
    delete page;
 
1556
 
 
1557
    m_mutex->unlock();
 
1558
 
 
1559
    return qMakePair(index, results);
 
1560
}