~adamreichold/qpdfview/trunk

360 by Adam Reichold
manual merge of future branch
1
/*
2
2124 by Adam Reichold
Add context menu item to append selected text to bookmark comment.
3
Copyright 2014, 2021 S. Razi Alavizadeh
2110 by Adam Reichold
Merge invert lightness functionality.
4
Copyright 2020 Johan Björklund
2113 by Adam Reichold
Fix broken preferences system menu item on macOS.
5
Copyright 2021 Vitaly Cheptsov
1650 by Adam Reichold
Expose custom PDF page label via the document view class.
6
Copyright 2013 Thomas Etter
2113 by Adam Reichold
Fix broken preferences system menu item on macOS.
7
Copyright 2012-2015, 2018, 2021 Adam Reichold
1505 by Adam Reichold
Add missing copyrights.
8
Copyright 2014 Dorian Scholz
2060 by Adam Reichold
Extend the database schema to store the paths currently expanded in the outline view.
9
Copyright 2018 Egor Zenkov
360 by Adam Reichold
manual merge of future branch
10
11
This file is part of qpdfview.
12
13
qpdfview is free software: you can redistribute it and/or modify
14
it under the terms of the GNU General Public License as published by
15
the Free Software Foundation, either version 2 of the License, or
16
(at your option) any later version.
17
18
qpdfview is distributed in the hope that it will be useful,
19
but WITHOUT ANY WARRANTY; without even the implied warranty of
20
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
GNU General Public License for more details.
22
23
You should have received a copy of the GNU General Public License
24
along with qpdfview.  If not, see <http://www.gnu.org/licenses/>.
25
26
*/
27
28
#include "documentview.h"
29
812 by Adam Reichold
continue simplifying headers
30
#include <QApplication>
31
#include <QInputDialog>
2007 by Adam Reichold
Extend the document properties with various miscellaneous file properties.
32
#include <QDateTime>
1046.1.49 by Adam Reichold
enhance presentation view history and reuse pages vector from parent
33
#include <QDebug>
812 by Adam Reichold
continue simplifying headers
34
#include <QDesktopServices>
815 by Adam Reichold
finished simplifying header handling
35
#include <QDir>
36
#include <QFileSystemWatcher>
812 by Adam Reichold
continue simplifying headers
37
#include <QKeyEvent>
815 by Adam Reichold
finished simplifying header handling
38
#include <qmath.h>
812 by Adam Reichold
continue simplifying headers
39
#include <QMenu>
40
#include <QMessageBox>
1389 by Adam Reichold
try to copy the CUPS options stored in the private print engine property under key 0xfe00
41
#include <QPrintEngine>
815 by Adam Reichold
finished simplifying header handling
42
#include <QProcess>
824 by Adam Reichold
end first integration of abstract model
43
#include <QProgressDialog>
812 by Adam Reichold
continue simplifying headers
44
#include <QScrollBar>
815 by Adam Reichold
finished simplifying header handling
45
#include <QTemporaryFile>
46
#include <QTimer>
47
#include <QUrl>
812 by Adam Reichold
continue simplifying headers
48
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
49
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
50
51
#include <QScreen>
52
53
#else
54
55
#include <QDesktopWidget>
56
57
#endif // QT_VERSION_CHECK
58
793.1.1 by Alexander Volkov
reduce header interdependence
59
#ifdef WITH_CUPS
60
61
#include <cups/cups.h>
1585 by Adam Reichold
Determine available color models of CUPS destination and try to request CMYK or RGB if available and color output was requested.
62
#include <cups/ppd.h>
793.1.1 by Alexander Volkov
reduce header interdependence
63
64
#endif // WITH_CUPS
65
66
#ifdef WITH_SYNCTEX
67
68
#include <synctex_parser.h>
69
2070 by Adam Reichold
Adapt for compatibility with SyncTeX parser version 1.19 and later.
70
#ifndef HAS_SYNCTEX_2
71
72
typedef synctex_scanner_t synctex_scanner_p;
73
typedef synctex_node_t synctex_node_p;
74
75
#define synctex_scanner_next_result(scanner) synctex_next_result(scanner)
76
77
#endif // HAS_SYNCTEX_2
78
793.1.1 by Alexander Volkov
reduce header interdependence
79
#endif // WITH_SYNCTEX
80
1046.1.43 by Adam Reichold
rename the new settings to just settings
81
#include "settings.h"
823 by Adam Reichold
begin integration of abstract model
82
#include "model.h"
1046.1.34 by Adam Reichold
refactor plug-in handling
83
#include "pluginhandler.h"
1104 by Adam Reichold
minor organizational shuffling
84
#include "shortcuthandler.h"
1561.1.16 by Adam Reichold
Use a separate source file for the thumbnail item class.
85
#include "thumbnailitem.h"
1046.1.31 by Adam Reichold
use a simpler render task object instead of QtConcurrentRun
86
#include "presentationview.h"
1719 by Adam Reichold
Merge central search model.
87
#include "searchmodel.h"
1046.1.32 by Adam Reichold
simplify search task
88
#include "searchtask.h"
1112 by Adam Reichold
use composition mode multiply for highlights
89
#include "miscellaneous.h"
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
90
#include "compatibility.h"
1348.1.1 by Adam Reichold
add document layout class following strategy pattern
91
#include "documentlayout.h"
793.1.1 by Alexander Volkov
reduce header interdependence
92
1561.1.20 by Adam Reichold
Make the unscaled size helper methods into actual anonymous helper methods.
93
namespace
94
{
95
96
using namespace qpdfview;
97
1658 by Adam Reichold
Merge branch to manually set first body matter page.
98
// taken from http://rosettacode.org/wiki/Roman_numerals/Decode#C.2B.2B
99
int romanToInt(const QString& text)
100
{
101
    if(text.size() == 1)
102
    {
103
        switch(text.at(0).toLower().toLatin1())
104
        {
105
        case 'i': return 1;
106
        case 'v': return 5;
107
        case 'x': return 10;
108
        case 'l': return 50;
109
        case 'c': return 100;
110
        case 'd': return 500;
111
        case 'm': return 1000;
112
        }
113
114
        return 0;
115
    }
116
117
    int result = 0;
118
    int previous = 0, current = 0;
119
120
    for(int i = text.size() - 1; i >= 0; --i)
121
    {
122
        current = romanToInt(text.at(i));
123
124
        result += current < previous ? -current : current;
125
126
        previous = current;
127
    }
128
129
    return result;
130
}
131
132
// taken from http://rosettacode.org/wiki/Roman_numerals/Encode#C.2B.2B
133
QString intToRoman(int number)
134
{
135
    struct romandata_t
136
    {
137
        int value;
138
        char const* numeral;
139
    };
140
141
    static const romandata_t romandata[] =
142
    {
1777 by Adam Reichold
Fix a compilation issue on ARM architecture due to 'qreal' being 'float' there.
143
        { 1000, "m" },
144
        { 900, "cm" },
145
        { 500, "d" },
146
        { 400, "cd" },
147
        { 100, "c" },
148
        { 90, "xc" },
149
        { 50, "l" },
150
        { 40, "xl" },
151
        { 10, "x" },
152
        { 9, "ix" },
153
        { 5, "v" },
154
        { 4, "iv" },
155
        { 1, "i" },
156
        { 0, NULL }
1658 by Adam Reichold
Merge branch to manually set first body matter page.
157
    };
158
159
    if(number >= 4000)
160
    {
161
        return QLatin1String("?");
162
    }
163
164
    QString result;
165
166
    for(const romandata_t* current = romandata; current->value > 0; ++current)
167
    {
168
        while(number >= current->value)
169
        {
170
            number -= current->value;
171
            result += QLatin1String(current->numeral);
172
        }
173
    }
174
175
    return result;
176
}
177
1894 by Adam Reichold
Move the actual file copying into a helper function.
178
bool copyFile(QFile& source, QFile& destination)
179
{
180
    const qint64 maxSize = 4096;
181
    qint64 size = -1;
182
183
    QScopedArrayPointer< char > buffer(new char[maxSize]);
184
185
    do
186
    {
187
        if((size = source.read(buffer.data(), maxSize)) < 0)
188
        {
189
            return false;
190
        }
191
192
        if(destination.write(buffer.data(), size) < 0)
193
        {
194
            return false;
195
        }
196
    }
197
    while(size > 0);
198
199
    return true;
200
}
201
1970 by Adam Reichold
Small reordering of document view helper functions.
202
inline void adjustFileTemplateSuffix(QTemporaryFile& temporaryFile, const QString& suffix)
203
{
204
    temporaryFile.setFileTemplate(temporaryFile.fileTemplate() + QLatin1String(".") + suffix);
205
}
206
1585 by Adam Reichold
Determine available color models of CUPS destination and try to request CMYK or RGB if available and color output was requested.
207
#ifdef WITH_CUPS
208
1590 by Adam Reichold
Try harder to prefer CMYK over RGB printing color model and have some RAII fun using custom deleters.
209
struct RemovePpdFileDeleter
210
{
211
    static inline void cleanup(const char* ppdFileName) { if(ppdFileName != 0) { QFile::remove(ppdFileName); } }
212
};
213
214
struct ClosePpdFileDeleter
215
{
216
    static inline void cleanup(ppd_file_t* ppdFile) { if(ppdFile != 0) { ppdClose(ppdFile); } }
217
};
218
1585 by Adam Reichold
Determine available color models of CUPS destination and try to request CMYK or RGB if available and color output was requested.
219
int addCMYKorRGBColorModel(cups_dest_t* dest, int num_options, cups_option_t** options)
220
{
1590 by Adam Reichold
Try harder to prefer CMYK over RGB printing color model and have some RAII fun using custom deleters.
221
    QScopedPointer< const char, RemovePpdFileDeleter > ppdFileName(cupsGetPPD(dest->name));
222
223
    if(ppdFileName.isNull())
224
    {
225
        return num_options;
226
    }
227
228
    QScopedPointer< ppd_file_t, ClosePpdFileDeleter > ppdFile(ppdOpenFile(ppdFileName.data()));
229
230
    if(ppdFile.isNull())
231
    {
232
        return num_options;
233
    }
234
235
    ppd_option_t* colorModel = ppdFindOption(ppdFile.data(), "ColorModel");
1585 by Adam Reichold
Determine available color models of CUPS destination and try to request CMYK or RGB if available and color output was requested.
236
237
    if(colorModel == 0)
238
    {
239
        return num_options;
240
    }
241
242
    for(int index = 0; index < colorModel->num_choices; ++index)
243
    {
1876 by Adam Reichold
Remove point less manual length counting of string literals.
244
        if(qstrcmp(colorModel->choices[index].choice, "CMYK") == 0)
1585 by Adam Reichold
Determine available color models of CUPS destination and try to request CMYK or RGB if available and color output was requested.
245
        {
1590 by Adam Reichold
Try harder to prefer CMYK over RGB printing color model and have some RAII fun using custom deleters.
246
            return cupsAddOption("ColorModel", "CMYK", num_options, options);
247
        }
248
    }
1585 by Adam Reichold
Determine available color models of CUPS destination and try to request CMYK or RGB if available and color output was requested.
249
1590 by Adam Reichold
Try harder to prefer CMYK over RGB printing color model and have some RAII fun using custom deleters.
250
    for(int index = 0; index < colorModel->num_choices; ++index)
251
    {
1876 by Adam Reichold
Remove point less manual length counting of string literals.
252
        if(qstrcmp(colorModel->choices[index].choice, "RGB") == 0)
1585 by Adam Reichold
Determine available color models of CUPS destination and try to request CMYK or RGB if available and color output was requested.
253
        {
1590 by Adam Reichold
Try harder to prefer CMYK over RGB printing color model and have some RAII fun using custom deleters.
254
            return cupsAddOption("ColorModel", "RGB", num_options, options);
1585 by Adam Reichold
Determine available color models of CUPS destination and try to request CMYK or RGB if available and color output was requested.
255
        }
256
    }
257
258
    return num_options;
259
}
260
261
#endif // WITH_CUPS
262
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
263
#ifdef WITH_SYNCTEX
264
2041.2.12 by Adam Reichold
Fix usage of QList in the bookmark and search models and various small performance issues reported by the clazy tool using the checks of "level0,level1,level2,no-missing-qobject-macro,no-qstring-allocations,no-copyable-polymorphic,no-ctor-missing-parent-argument,no-reserve-candidates".
265
DocumentView::SourceLink scanForSourceLink(const QString& filePath, const int page, QPointF pos)
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
266
{
267
    DocumentView::SourceLink sourceLink;
268
2070 by Adam Reichold
Adapt for compatibility with SyncTeX parser version 1.19 and later.
269
    if(synctex_scanner_p scanner = synctex_scanner_new_with_output_file(filePath.toLocal8Bit(), 0, 1))
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
270
    {
271
        if(synctex_edit_query(scanner, page, pos.x(), pos.y()) > 0)
272
        {
2070 by Adam Reichold
Adapt for compatibility with SyncTeX parser version 1.19 and later.
273
            for(synctex_node_p node = synctex_scanner_next_result(scanner); node != 0; node = synctex_scanner_next_result(scanner))
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
274
            {
275
                sourceLink.name = QString::fromLocal8Bit(synctex_scanner_get_name(scanner, synctex_node_tag(node)));
276
                sourceLink.line = qMax(synctex_node_line(node), 0);
277
                sourceLink.column = qMax(synctex_node_column(node), 0);
278
                break;
279
            }
280
        }
281
282
        synctex_scanner_free(scanner);
283
    }
284
285
    return sourceLink;
286
}
287
288
#endif // WITH_SYNCTEX
289
2041.2.12 by Adam Reichold
Fix usage of QList in the bookmark and search models and various small performance issues reported by the clazy tool using the checks of "level0,level1,level2,no-missing-qobject-macro,no-qstring-allocations,no-copyable-polymorphic,no-ctor-missing-parent-argument,no-reserve-candidates".
290
inline bool modifiersAreActive(const QWheelEvent* event, Qt::KeyboardModifiers modifiers)
1980 by Adam Reichold
Do some copy editing of the mouse and key event handling for better readability.
291
{
292
    if(modifiers == Qt::NoModifier)
293
    {
294
        return false;
295
    }
296
297
    return event->modifiers() == modifiers || (event->buttons() & modifiers) != 0;
298
}
299
1970 by Adam Reichold
Small reordering of document view helper functions.
300
inline bool modifiersUseMouseButton(Settings* settings, Qt::MouseButton mouseButton)
1690 by Adam Reichold
Enable the use of the right mouse button as a modifier.
301
{
302
    return ((settings->documentView().zoomModifiers() | settings->documentView().rotateModifiers() | settings->documentView().scrollModifiers()) & mouseButton) != 0;
303
}
304
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
305
inline void adjustScaleFactor(RenderParam& renderParam, qreal scaleFactor)
306
{
307
    if(!qFuzzyCompare(renderParam.scaleFactor(), scaleFactor))
308
    {
309
        renderParam.setScaleFactor(scaleFactor);
310
    }
311
}
312
1881.1.4 by Adam Reichold
Add setting to scroll only if the target value is not yet visible.
313
inline void setValueIfNotVisible(QScrollBar* scrollBar, int value)
314
{
315
    if(value < scrollBar->value() || value > scrollBar->value() + scrollBar->pageStep())
316
    {
317
        scrollBar->setValue(value);
318
    }
319
}
320
1970 by Adam Reichold
Small reordering of document view helper functions.
321
inline int pageOfResult(const QModelIndex& index)
322
{
323
    return index.data(SearchModel::PageRole).toInt();
324
}
325
326
inline QRectF rectOfResult(const QModelIndex& index)
327
{
328
    return index.data(SearchModel::RectRole).toRectF();
329
}
330
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
331
class OutlineModel : public QAbstractItemModel
332
{
333
public:
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
334
    OutlineModel(const Model::Outline& outline, DocumentView* parent) : QAbstractItemModel(parent),
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
335
        m_outline(outline)
336
    {
337
    }
338
339
    QModelIndex index(int row, int column, const QModelIndex& parent) const
340
    {
341
        if(!hasIndex(row, column, parent))
342
        {
343
            return QModelIndex();
344
        }
345
346
        if(parent.isValid())
347
        {
348
            const Model::Section* section = resolveIndex(parent);
349
350
            return createIndex(row, column, &section->children);
351
        }
352
        else
353
        {
354
            return createIndex(row, column, &m_outline);
355
        }
356
    }
357
358
    QModelIndex parent(const QModelIndex& child) const
359
    {
360
        if(!child.isValid())
361
        {
362
            return QModelIndex();
363
        }
364
365
        const Model::Outline* children = static_cast< const Model::Outline* >(child.internalPointer());
366
367
        if(&m_outline != children)
368
        {
369
            return findParent(&m_outline, children);
370
        }
371
372
        return QModelIndex();
373
    }
374
375
    int columnCount(const QModelIndex&) const
376
    {
377
        return 2;
378
    }
379
380
    int rowCount(const QModelIndex& parent) const
381
    {
382
        if(parent.isValid())
383
        {
384
            const Model::Section* section = resolveIndex(parent);
385
386
            return section->children.size();
387
        }
388
        else
389
        {
390
            return m_outline.size();
391
        }
392
    }
393
394
    QVariant data(const QModelIndex& index, int role) const
395
    {
396
        if(!index.isValid())
397
        {
398
            return QVariant();
399
        }
400
401
        const Model::Section* section = resolveIndex(index);
402
403
        switch(role)
404
        {
405
        case Qt::DisplayRole:
406
            switch(index.column())
407
            {
408
            case 0:
409
                return section->title;
410
            case 1:
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
411
                return pageLabel(section->link.page);
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
412
            default:
413
                return QVariant();
414
            }
415
        case Model::Document::PageRole:
416
            return section->link.page;
417
        case Model::Document::LeftRole:
418
            return section->link.left;
419
        case Model::Document::TopRole:
420
            return section->link.top;
421
        case Model::Document::FileNameRole:
422
            return section->link.urlOrFileName;
423
        case Model::Document::ExpansionRole:
424
            return m_expanded.contains(section);
425
        default:
426
            return QVariant();
427
        }
428
    }
429
430
    bool setData(const QModelIndex& index, const QVariant& value, int role)
431
    {
432
        if(!index.isValid() || role != Model::Document::ExpansionRole)
433
        {
434
            return false;
435
        }
436
437
        const Model::Section* section = resolveIndex(index);
438
439
        if(value.toBool())
440
        {
441
            m_expanded.insert(section);
442
        }
443
        else
444
        {
445
            m_expanded.remove(section);
446
        }
447
448
        return true;
449
    }
450
451
private:
452
    const Model::Outline m_outline;
453
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
454
    DocumentView* documentView() const
455
    {
456
        return static_cast< DocumentView* >(QObject::parent());
457
    }
458
459
    QString pageLabel(int pageNumber) const
460
    {
461
        return documentView()->pageLabelFromNumber(pageNumber);
462
    }
463
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
464
    QSet< const Model::Section* > m_expanded;
465
466
    const Model::Section* resolveIndex(const QModelIndex& index) const
467
    {
468
        return &static_cast< const Model::Outline* >(index.internalPointer())->at(index.row());
469
    }
470
471
    QModelIndex createIndex(int row, int column, const Model::Outline* outline) const
472
    {
473
        return QAbstractItemModel::createIndex(row, column, const_cast< void* >(static_cast< const void* >(outline)));
474
    }
475
476
    QModelIndex findParent(const Model::Outline* outline, const Model::Outline* children) const
477
    {
478
        for(Model::Outline::const_iterator section = outline->begin(); section != outline->end(); ++section)
479
        {
480
            if(&section->children == children)
481
            {
482
                return createIndex(section - outline->begin(), 0, outline);
483
            }
484
        }
485
486
        for(Model::Outline::const_iterator section = outline->begin(); section != outline->end(); ++section)
487
        {
488
            const QModelIndex parent = findParent(&section->children, children);
489
490
            if(parent.isValid())
491
            {
492
                return parent;
493
            }
494
        }
495
496
        return QModelIndex();
497
    }
498
499
};
500
501
class FallbackOutlineModel : public QAbstractTableModel
502
{
503
public:
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
504
    FallbackOutlineModel(DocumentView* parent) : QAbstractTableModel(parent)
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
505
    {
506
    }
507
508
    int columnCount(const QModelIndex&) const
509
    {
510
        return 2;
511
    }
512
513
    int rowCount(const QModelIndex& parent) const
514
    {
515
        if(parent.isValid())
516
        {
517
            return 0;
518
        }
519
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
520
        return numberOfPages();
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
521
    }
522
523
    QVariant data(const QModelIndex& index, int role) const
524
    {
525
        if(!index.isValid())
526
        {
527
            return QVariant();
528
        }
529
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
530
        const int pageNumber = index.row() + 1;
531
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
532
        switch(role)
533
        {
534
        case Qt::DisplayRole:
535
            switch(index.column())
536
            {
537
            case 0:
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
538
                return DocumentView::tr("Page %1").arg(pageLabel(pageNumber));
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
539
            case 1:
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
540
                return pageLabel(pageNumber);
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
541
            default:
542
                return QVariant();
543
            }
544
        case Model::Document::PageRole:
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
545
            return pageNumber;
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
546
        case Model::Document::LeftRole:
547
        case Model::Document::TopRole:
548
            return qQNaN();
549
        default:
550
            return QVariant();
551
        }
552
    }
553
554
private:
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
555
    DocumentView* documentView() const
556
    {
557
        return static_cast< DocumentView* >(QObject::parent());
558
    }
559
560
    int numberOfPages() const
561
    {
562
        return documentView()->numberOfPages();
563
    }
564
565
    QString pageLabel(int pageNumber) const
566
    {
567
        return documentView()->pageLabelFromNumber(pageNumber);
568
    }
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
569
570
};
571
572
class PropertiesModel : public QAbstractTableModel
573
{
574
public:
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
575
    PropertiesModel(const Model::Properties& properties, DocumentView* parent = 0) : QAbstractTableModel(parent),
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
576
        m_properties(properties)
577
    {
578
    }
579
580
    int columnCount(const QModelIndex&) const
581
    {
582
        return 2;
583
    }
584
585
    int rowCount(const QModelIndex& parent) const
586
    {
587
        if(parent.isValid())
588
        {
589
            return 0;
590
        }
591
592
        return m_properties.size();
593
    }
594
595
    QVariant data(const QModelIndex& index, int role) const
596
    {
597
        if(!index.isValid() || role != Qt::DisplayRole)
598
        {
599
            return QVariant();
600
        }
601
602
        switch (index.column())
603
        {
604
        case 0:
605
            return m_properties[index.row()].first;
606
        case 1:
607
            return m_properties[index.row()].second;
608
        default:
609
            return QVariant();
610
        }
611
    }
612
613
private:
614
    const Model::Properties m_properties;
615
616
};
617
2008 by Adam Reichold
Fix some unintended formatting irregularities.
618
void addProperty(Model::Properties& properties, const char* name, const QString& value)
2007 by Adam Reichold
Extend the document properties with various miscellaneous file properties.
619
{
620
    properties.append(qMakePair(DocumentView::tr(name), value));
621
}
622
2008 by Adam Reichold
Fix some unintended formatting irregularities.
623
QString formatFileSize(qint64 size)
2007 by Adam Reichold
Extend the document properties with various miscellaneous file properties.
624
{
625
    static const char* const units[] = { "B", "kB", "MB", "GB" };
626
    static const char* const* const lastUnit = &units[sizeof(units) / sizeof(units[0]) - 1];
627
    const char* const* unit = &units[0];
628
629
    while(size > 2048 && unit < lastUnit)
630
    {
631
        size /= 1024;
632
        unit++;
633
    }
634
635
    return QString("%1 %2").arg(size).arg(*unit);
636
}
637
2008 by Adam Reichold
Fix some unintended formatting irregularities.
638
void addFileProperties(Model::Properties& properties, const QFileInfo& fileInfo)
2007 by Adam Reichold
Extend the document properties with various miscellaneous file properties.
639
{
640
    addProperty(properties, "File path", fileInfo.absoluteFilePath());
641
    addProperty(properties, "File size", formatFileSize(fileInfo.size()));
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
642
643
#if QT_VERSION >= QT_VERSION_CHECK(5,10,0)
644
645
    addProperty(properties, "File created", fileInfo.birthTime().toString());
646
647
#else
648
2007 by Adam Reichold
Extend the document properties with various miscellaneous file properties.
649
    addProperty(properties, "File created", fileInfo.created().toString());
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
650
651
#endif // QT_VERSION
652
2007 by Adam Reichold
Extend the document properties with various miscellaneous file properties.
653
    addProperty(properties, "File last modified", fileInfo.lastModified().toString());
654
    addProperty(properties, "File owner", fileInfo.owner());
655
    addProperty(properties, "File group", fileInfo.owner());
656
}
657
2060 by Adam Reichold
Extend the database schema to store the paths currently expanded in the outline view.
658
void appendToPath(const QModelIndex& index, QByteArray& path)
1803.1.1 by Adam Reichold
Restore expanded paths within outline after refreshing document.
659
{
2059.1.2 by angelforest
Save outline state as byte arrays in separate table
660
    path.append(index.data(Qt::DisplayRole).toByteArray()).append('\0');
2060 by Adam Reichold
Extend the database schema to store the paths currently expanded in the outline view.
661
}
662
663
void saveExpandedPaths(const QAbstractItemModel* model, QSet< QByteArray >& paths, const QModelIndex& index = QModelIndex(), QByteArray path = QByteArray())
664
{
665
    appendToPath(index, path);
1803.1.1 by Adam Reichold
Restore expanded paths within outline after refreshing document.
666
1803.1.4 by Adam Reichold
Do some more micro-optimizations to iterating item models.
667
    if(model->data(index, Model::Document::ExpansionRole).toBool())
1803.1.1 by Adam Reichold
Restore expanded paths within outline after refreshing document.
668
    {
669
        paths.insert(path);
670
    }
671
672
    for(int row = 0, rowCount = model->rowCount(index); row < rowCount; ++row)
673
    {
674
        saveExpandedPaths(model, paths, model->index(row, 0, index), path);
675
    }
676
}
677
2060 by Adam Reichold
Extend the database schema to store the paths currently expanded in the outline view.
678
void restoreExpandedPaths(QAbstractItemModel* model, const QSet< QByteArray >& paths, const QModelIndex& index = QModelIndex(), QByteArray path = QByteArray())
1803.1.1 by Adam Reichold
Restore expanded paths within outline after refreshing document.
679
{
2060 by Adam Reichold
Extend the database schema to store the paths currently expanded in the outline view.
680
    appendToPath(index, path);
1803.1.1 by Adam Reichold
Restore expanded paths within outline after refreshing document.
681
682
    if(paths.contains(path))
683
    {
1803.1.3 by Adam Reichold
Move outline item data roles into document model to limit its scope.
684
        model->setData(index, true, Model::Document::ExpansionRole);
1803.1.1 by Adam Reichold
Restore expanded paths within outline after refreshing document.
685
    }
686
687
    for(int row = 0, rowCount = model->rowCount(index); row < rowCount; ++row)
688
    {
689
        restoreExpandedPaths(model, paths, model->index(row, 0, index), path);
690
    }
691
}
692
1561.1.20 by Adam Reichold
Make the unscaled size helper methods into actual anonymous helper methods.
693
} // anonymous
694
1518 by Adam Reichold
Make proper use of application and anonymous namespaces and fix a few header guards.
695
namespace qpdfview
696
{
697
2041.2.9 by Adam Reichold
Instead of disconnecting and reconnecting slots to avoid redundant updates, block the signle relevant slot using a simple flag variable and an RAII helper.
698
class DocumentView::VerticalScrollBarChangedBlocker
699
{
2041.2.12 by Adam Reichold
Fix usage of QList in the bookmark and search models and various small performance issues reported by the clazy tool using the checks of "level0,level1,level2,no-missing-qobject-macro,no-qstring-allocations,no-copyable-polymorphic,no-ctor-missing-parent-argument,no-reserve-candidates".
700
    Q_DISABLE_COPY(VerticalScrollBarChangedBlocker)
701
2041.2.9 by Adam Reichold
Instead of disconnecting and reconnecting slots to avoid redundant updates, block the signle relevant slot using a simple flag variable and an RAII helper.
702
private:
703
    DocumentView* const that;
704
705
public:
706
707
    VerticalScrollBarChangedBlocker(DocumentView* that) : that(that)
708
    {
709
        that->m_verticalScrollBarChangedBlocked = true;
710
    }
711
712
    ~VerticalScrollBarChangedBlocker()
713
    {
714
        that->m_verticalScrollBarChangedBlocked = false;
715
    }
716
717
};
718
1046.1.43 by Adam Reichold
rename the new settings to just settings
719
Settings* DocumentView::s_settings = 0;
1103 by Adam Reichold
move the last keyboard shortcut handling out of the document view and
720
ShortcutHandler* DocumentView::s_shortcutHandler = 0;
1717.1.2 by Razi Alavizadeh
Add a central search model to store search results.
721
SearchModel* DocumentView::s_searchModel = 0;
1025 by Adam Reichold
make movement shortcuts configurable as well and hence remove hard-coded Vim-style movement shortcuts
722
360 by Adam Reichold
manual merge of future branch
723
DocumentView::DocumentView(QWidget* parent) : QGraphicsView(parent),
366 by Adam Reichold
add prefetch and make culling thread-safe
724
    m_autoRefreshWatcher(0),
725
    m_autoRefreshTimer(0),
414 by Adam Reichold
move settings handling out of the document view into the main window
726
    m_prefetchTimer(0),
360 by Adam Reichold
manual merge of future branch
727
    m_document(0),
1046.1.57 by Adam Reichold
small refactoring of presentation view, using QList instead QVector to
728
    m_pages(),
1413 by Adam Reichold
Store a QFileInfo instead of a plain path in the document view to reduce the number of temporary objects.
729
    m_fileInfo(),
730
    m_wasModified(false),
360 by Adam Reichold
manual merge of future branch
731
    m_currentPage(-1),
1658 by Adam Reichold
Merge branch to manually set first body matter page.
732
    m_firstPage(-1),
1046.1.48 by Adam Reichold
enhance history mechanism for jumping backward and forward
733
    m_past(),
734
    m_future(),
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
735
    m_layout(new SinglePageLayout),
360 by Adam Reichold
manual merge of future branch
736
    m_continuousMode(false),
814 by Adam Reichold
move document view enumerations and print options to global header
737
    m_scaleMode(ScaleFactorMode),
360 by Adam Reichold
manual merge of future branch
738
    m_scaleFactor(1.0),
818 by Adam Reichold
move print options into separate header and rename rotation enum slightly
739
    m_rotation(RotateBy0),
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
740
    m_renderFlags(),
360 by Adam Reichold
manual merge of future branch
741
    m_highlightAll(false),
813 by Adam Reichold
move page item enumerations into global header
742
    m_rubberBandMode(ModifiersMode),
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
743
    m_pageItems(),
744
    m_thumbnailItems(),
1046.1.3 by Adam Reichold
simplify scene management
745
    m_highlight(0),
1923.1.4 by Adam Reichold
Communicate the thumbnails viewport size via an explicit property to have more flexibility in the future to decide which viewport determines scaling.
746
    m_thumbnailsViewportSize(),
1209 by Adam Reichold
make thumbnails layout orientation adjust according to dock orientation
747
    m_thumbnailsOrientation(Qt::Vertical),
360 by Adam Reichold
manual merge of future branch
748
    m_thumbnailsScene(0),
749
    m_outlineModel(0),
750
    m_propertiesModel(0),
2041.2.9 by Adam Reichold
Instead of disconnecting and reconnecting slots to avoid redundant updates, block the signle relevant slot using a simple flag variable and an RAII helper.
751
    m_verticalScrollBarChangedBlocked(false),
1781 by Adam Reichold
Fix a compilation warning and expose search progress via item model data role.
752
    m_currentResult(),
753
    m_searchTask(0)
360 by Adam Reichold
manual merge of future branch
754
{
1046.1.41 by Adam Reichold
begin transition to the new settings class
755
    if(s_settings == 0)
756
    {
1046.1.43 by Adam Reichold
rename the new settings to just settings
757
        s_settings = Settings::instance();
1046.1.41 by Adam Reichold
begin transition to the new settings class
758
    }
759
1103 by Adam Reichold
move the last keyboard shortcut handling out of the document view and
760
    if(s_shortcutHandler == 0)
761
    {
762
        s_shortcutHandler = ShortcutHandler::instance();
763
    }
764
1717.1.2 by Razi Alavizadeh
Add a central search model to store search results.
765
    if(s_searchModel == 0)
766
    {
767
        s_searchModel = SearchModel::instance();
768
    }
769
1046.1.3 by Adam Reichold
simplify scene management
770
    setScene(new QGraphicsScene(this));
360 by Adam Reichold
manual merge of future branch
771
2041.2.1 by Adam Reichold
Add the possiblity to split the document views below the tabs for reading two documents side by side.
772
    setFocusPolicy(Qt::StrongFocus);
1040 by Adam Reichold
small style improvements for document view
773
    setAcceptDrops(false);
360 by Adam Reichold
manual merge of future branch
774
    setDragMode(QGraphicsView::ScrollHandDrag);
775
2041.2.9 by Adam Reichold
Instead of disconnecting and reconnecting slots to avoid redundant updates, block the signle relevant slot using a simple flag variable and an RAII helper.
776
    connect(verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(on_verticalScrollBar_valueChanged()));
360 by Adam Reichold
manual merge of future branch
777
1046.1.3 by Adam Reichold
simplify scene management
778
    m_thumbnailsScene = new QGraphicsScene(this);
779
360 by Adam Reichold
manual merge of future branch
780
    // highlight
781
782
    m_highlight = new QGraphicsRectItem();
1128 by Adam Reichold
expose the highlight color setting and make sure to activate it on each highlighting change
783
    m_highlight->setGraphicsEffect(new GraphicsCompositionModeEffect(QPainter::CompositionMode_Multiply, this));
360 by Adam Reichold
manual merge of future branch
784
785
    m_highlight->setVisible(false);
1046.1.3 by Adam Reichold
simplify scene management
786
    scene()->addItem(m_highlight);
360 by Adam Reichold
manual merge of future branch
787
788
    // search
789
1046.1.32 by Adam Reichold
simplify search task
790
    m_searchTask = new SearchTask(this);
791
792
    connect(m_searchTask, SIGNAL(finished()), SIGNAL(searchFinished()));
793
1782 by Adam Reichold
Paint search progress in the document items of the extended search dock view.
794
    connect(m_searchTask, SIGNAL(progressChanged(int)), SLOT(on_searchTask_progressChanged(int)));
1046.1.32 by Adam Reichold
simplify search task
795
    connect(m_searchTask, SIGNAL(resultsReady(int,QList<QRectF>)), SLOT(on_searchTask_resultsReady(int,QList<QRectF>)));
360 by Adam Reichold
manual merge of future branch
796
414 by Adam Reichold
move settings handling out of the document view into the main window
797
    // auto-refresh
798
799
    m_autoRefreshWatcher = new QFileSystemWatcher(this);
620 by Adam Reichold
results of a fast review of all source files
800
414 by Adam Reichold
move settings handling out of the document view into the main window
801
    m_autoRefreshTimer = new QTimer(this);
1138 by Adam Reichold
Make auto-refresh and prefetch timeout configurable (via the
802
    m_autoRefreshTimer->setInterval(s_settings->documentView().autoRefreshTimeout());
414 by Adam Reichold
move settings handling out of the document view into the main window
803
    m_autoRefreshTimer->setSingleShot(true);
804
805
    connect(m_autoRefreshWatcher, SIGNAL(fileChanged(QString)), m_autoRefreshTimer, SLOT(start()));
953 by Adam Reichold
results of a first glancing review preparing for the next beta release
806
1531 by Adam Reichold
Check for deletion before issueing auto-refresh.
807
    connect(m_autoRefreshTimer, SIGNAL(timeout()), this, SLOT(on_autoRefresh_timeout()));
414 by Adam Reichold
move settings handling out of the document view into the main window
808
366 by Adam Reichold
add prefetch and make culling thread-safe
809
    // prefetch
810
811
    m_prefetchTimer = new QTimer(this);
1138 by Adam Reichold
Make auto-refresh and prefetch timeout configurable (via the
812
    m_prefetchTimer->setInterval(s_settings->documentView().prefetchTimeout());
366 by Adam Reichold
add prefetch and make culling thread-safe
813
    m_prefetchTimer->setSingleShot(true);
814
815
    connect(this, SIGNAL(currentPageChanged(int)), m_prefetchTimer, SLOT(start()));
814 by Adam Reichold
move document view enumerations and print options to global header
816
    connect(this, SIGNAL(layoutModeChanged(LayoutMode)), m_prefetchTimer, SLOT(start()));
817
    connect(this, SIGNAL(scaleModeChanged(ScaleMode)), m_prefetchTimer, SLOT(start()));
366 by Adam Reichold
add prefetch and make culling thread-safe
818
    connect(this, SIGNAL(scaleFactorChanged(qreal)), m_prefetchTimer, SLOT(start()));
813 by Adam Reichold
move page item enumerations into global header
819
    connect(this, SIGNAL(rotationChanged(Rotation)), m_prefetchTimer, SLOT(start()));
1973 by Adam Reichold
Trigger prefetch for every render flag change, not just color inversion.
820
    connect(this, SIGNAL(renderFlagsChanged(qpdfview::RenderFlags)), m_prefetchTimer, SLOT(start()));
366 by Adam Reichold
add prefetch and make culling thread-safe
821
822
    connect(m_prefetchTimer, SIGNAL(timeout()), SLOT(on_prefetch_timeout()));
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
823
824
    // settings
825
826
    m_continuousMode = s_settings->documentView().continuousMode();
827
    m_layout.reset(DocumentLayout::fromLayoutMode(s_settings->documentView().layoutMode()));
1472 by Adam Reichold
Use a weaker notion of defaulting to right-to-left on right-to-left locales to remove non-uniformity of handling settings.
828
    m_rightToLeftMode = s_settings->documentView().rightToLeftMode();
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
829
830
    m_scaleMode = s_settings->documentView().scaleMode();
831
    m_scaleFactor = s_settings->documentView().scaleFactor();
832
    m_rotation = s_settings->documentView().rotation();
833
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
834
    if(s_settings->documentView().invertColors())
835
    {
836
        m_renderFlags |= InvertColors;
837
    }
838
2108.1.2 by Johan Björklund
Name change to "Invert lightness" and other fixes
839
    if(s_settings->documentView().invertLightness())
2108.1.1 by Johan Björklund
Invert light
840
    {
2108.1.2 by Johan Björklund
Name change to "Invert lightness" and other fixes
841
        m_renderFlags |= InvertLightness;
2108.1.1 by Johan Björklund
Invert light
842
    }
2108.1.2 by Johan Björklund
Name change to "Invert lightness" and other fixes
843
    
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
844
    if(s_settings->documentView().convertToGrayscale())
845
    {
846
        m_renderFlags |= ConvertToGrayscale;
847
    }
848
849
    if(s_settings->documentView().trimMargins())
850
    {
851
        m_renderFlags |= TrimMargins;
852
    }
853
854
    switch(s_settings->documentView().compositionMode())
855
    {
856
    default:
857
    case DefaultCompositionMode:
858
        break;
859
    case DarkenWithPaperColorMode:
860
        m_renderFlags |= DarkenWithPaperColor;
861
        break;
862
    case LightenWithPaperColorMode:
863
        m_renderFlags |= LightenWithPaperColor;
864
        break;
865
    }
1898.2.4 by Adam Reichold
Make the composition mode a per-tab property.
866
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
867
    m_highlightAll = s_settings->documentView().highlightAll();
360 by Adam Reichold
manual merge of future branch
868
}
869
870
DocumentView::~DocumentView()
871
{
1778 by Adam Reichold
Provide separate slots for search cancellation and clearing of search results.
872
    m_searchTask->cancel();
873
    m_searchTask->wait();
874
875
    s_searchModel->clearResults(this);
543 by Adam Reichold
fix a bug where the program crashes on refresh if highlight all is enabled
876
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
877
    qDeleteAll(m_pageItems);
878
    qDeleteAll(m_thumbnailItems);
879
360 by Adam Reichold
manual merge of future branch
880
    qDeleteAll(m_pages);
797 by Adam Reichold
remove unnecessary checks for null pointer before delete
881
    delete m_document;
360 by Adam Reichold
manual merge of future branch
882
}
883
1658 by Adam Reichold
Merge branch to manually set first body matter page.
884
void DocumentView::setFirstPage(int firstPage)
885
{
886
    if(m_firstPage != firstPage)
887
    {
888
        m_firstPage = firstPage;
889
1713 by Adam Reichold
Just update the thumbnail text instead of reconstruction.
890
        for(int index = 0; index < m_thumbnailItems.count(); ++index)
891
        {
892
            m_thumbnailItems.at(index)->setText(pageLabelFromNumber(index + 1));
893
        }
1658 by Adam Reichold
Merge branch to manually set first body matter page.
894
895
        prepareThumbnailsScene();
896
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
897
        emit numberOfPagesChanged(m_pages.count());
1658 by Adam Reichold
Merge branch to manually set first body matter page.
898
        emit currentPageChanged(m_currentPage);
899
    }
900
}
901
1655 by Adam Reichold
Adjust current page spin box suffix based on whether there is a non-trivial page label.
902
QString DocumentView::defaultPageLabelFromNumber(int number) const
903
{
904
    QLocale modifiedLocale = locale();
905
906
    modifiedLocale.setNumberOptions(modifiedLocale.numberOptions() | QLocale::OmitGroupSeparator);
907
908
    return modifiedLocale.toString(number);
909
}
910
1650 by Adam Reichold
Expose custom PDF page label via the document view class.
911
QString DocumentView::pageLabelFromNumber(int number) const
912
{
1658 by Adam Reichold
Merge branch to manually set first body matter page.
913
    QString label;
1650 by Adam Reichold
Expose custom PDF page label via the document view class.
914
1658 by Adam Reichold
Merge branch to manually set first body matter page.
915
    if(hasFrontMatter())
1650 by Adam Reichold
Expose custom PDF page label via the document view class.
916
    {
1717.1.1 by Razi Alavizadeh
Remove parts of code related to storing search results, and just use received results for highlighting.
917
        if(number < m_firstPage)
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
918
        {
1658 by Adam Reichold
Merge branch to manually set first body matter page.
919
            label = number < 4000 ? intToRoman(number) : defaultPageLabelFromNumber(-number);
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
920
        }
921
        else
922
        {
1658 by Adam Reichold
Merge branch to manually set first body matter page.
923
            label = defaultPageLabelFromNumber(number - m_firstPage + 1);
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
924
        }
1650 by Adam Reichold
Expose custom PDF page label via the document view class.
925
    }
1658 by Adam Reichold
Merge branch to manually set first body matter page.
926
    else if(number >= 1 && number <= m_pages.count())
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
927
    {
1710 by Adam Reichold
Improve locale-awareness of page labels.
928
        const QString& pageLabel = m_pages.at(number - 1)->label();
929
930
        if(number != pageLabel.toInt())
931
        {
932
            label = pageLabel;
933
        }
1650 by Adam Reichold
Expose custom PDF page label via the document view class.
934
    }
935
1658 by Adam Reichold
Merge branch to manually set first body matter page.
936
    if(label.isEmpty())
937
    {
938
        label = defaultPageLabelFromNumber(number);
939
    }
940
1650 by Adam Reichold
Expose custom PDF page label via the document view class.
941
    return label;
942
}
943
944
int DocumentView::pageNumberFromLabel(const QString& label) const
945
{
1658 by Adam Reichold
Merge branch to manually set first body matter page.
946
    if(hasFrontMatter())
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
947
    {
1658 by Adam Reichold
Merge branch to manually set first body matter page.
948
        bool ok = false;
949
        int value = locale().toInt(label, &ok);
950
951
        if(ok)
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
952
        {
1658 by Adam Reichold
Merge branch to manually set first body matter page.
953
            if(value < 0)
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
954
            {
1658 by Adam Reichold
Merge branch to manually set first body matter page.
955
                value = -value; // front matter
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
956
            }
957
            else
958
            {
1658 by Adam Reichold
Merge branch to manually set first body matter page.
959
                value = value + m_firstPage - 1; // body matter
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
960
            }
961
        }
962
        else
963
        {
1658 by Adam Reichold
Merge branch to manually set first body matter page.
964
            value = romanToInt(label);
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
965
        }
966
1658 by Adam Reichold
Merge branch to manually set first body matter page.
967
        return value;
1657.1.1 by Razi Alavizadeh
Added support to use and set visual page numbers.
968
    }
969
1650 by Adam Reichold
Expose custom PDF page label via the document view class.
970
    for(int index = 0; index < m_pages.count(); ++index)
971
    {
972
        if(m_pages.at(index)->label() == label)
973
        {
974
            return index + 1;
975
        }
976
    }
977
1653 by Adam Reichold
Actually connect up the mapping spin and solve the reparenting issue.
978
    return locale().toInt(label);
1650 by Adam Reichold
Expose custom PDF page label via the document view class.
979
}
980
1728 by Adam Reichold
Move tab title logic into document view so that the search model can access this property.
981
QString DocumentView::title() const
982
{
983
    QString title;
984
985
    if(s_settings->mainWindow().documentTitleAsTabTitle())
986
    {
1805 by Adam Reichold
Small performance improvement to document title extraction from properties.
987
        for(int row = 0, rowCount = m_propertiesModel->rowCount(); row < rowCount; ++row)
1728 by Adam Reichold
Move tab title logic into document view so that the search model can access this property.
988
        {
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
989
            const QString key = m_propertiesModel->index(row, 0).data().toString();
990
            const QString value = m_propertiesModel->index(row, 1).data().toString();
1805 by Adam Reichold
Small performance improvement to document title extraction from properties.
991
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
992
            if(QLatin1String("Title") == key)
1805 by Adam Reichold
Small performance improvement to document title extraction from properties.
993
            {
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
994
                title = value;
1805 by Adam Reichold
Small performance improvement to document title extraction from properties.
995
                break;
996
            }
1728 by Adam Reichold
Move tab title logic into document view so that the search model can access this property.
997
        }
998
    }
999
1000
    if(title.isEmpty())
1001
    {
1002
        title = m_fileInfo.completeBaseName();
1003
    }
1004
2113 by Adam Reichold
Fix broken preferences system menu item on macOS.
1005
#ifdef Q_OS_MAC
1006
1007
    // On macOS, some Qt versions have a bug of automatically detecting tab entries
1008
    // as menu entries with roles, causing opening files with these names to result
1009
    // in the "Preferences" menu item breaking.
1010
    title.prepend(QChar(0x200B));
1011
2115 by Adam Reichold
Fix patch wrangling error in macOS workaround.
1012
#endif // Q_OS_MAC
2113 by Adam Reichold
Fix broken preferences system menu item on macOS.
1013
1728 by Adam Reichold
Move tab title logic into document view so that the search model can access this property.
1014
    return title;
1015
}
1016
852 by Adam Reichold
load pre-defined plug-ins on-demand instead of at startup
1017
QStringList DocumentView::openFilter()
846 by Adam Reichold
added plug-in infrastructure
1018
{
1895 by Adam Reichold
Move the open filter into the plugin handler.
1019
    return PluginHandler::openFilter();
846 by Adam Reichold
added plug-in infrastructure
1020
}
1021
1022
QStringList DocumentView::saveFilter() const
1023
{
1024
    return m_document->saveFilter();
1025
}
1026
826 by Adam Reichold
improve format awareness of the UI in a few places
1027
bool DocumentView::canSave() const
1028
{
1029
    return m_document->canSave();
1030
}
1031
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1032
void DocumentView::setContinuousMode(bool continuousMode)
360 by Adam Reichold
manual merge of future branch
1033
{
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1034
    if(m_continuousMode != continuousMode)
360 by Adam Reichold
manual merge of future branch
1035
    {
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1036
        m_continuousMode = continuousMode;
360 by Adam Reichold
manual merge of future branch
1037
402 by Adam Reichold
save position on continuous mode change
1038
        qreal left = 0.0, top = 0.0;
1039
        saveLeftAndTop(left, top);
1040
1608 by Adam Reichold
Instead of always showing the vertical scroll bar for simpler visble area calculations, adjust the scroll bar policy based on the scale mode.
1041
        adjustScrollBarPolicy();
1042
402 by Adam Reichold
save position on continuous mode change
1043
        prepareView(left, top);
360 by Adam Reichold
manual merge of future branch
1044
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1045
        emit continuousModeChanged(m_continuousMode);
1046
1047
        s_settings->documentView().setContinuousMode(m_continuousMode);
360 by Adam Reichold
manual merge of future branch
1048
    }
1049
}
1050
814 by Adam Reichold
move document view enumerations and print options to global header
1051
LayoutMode DocumentView::layoutMode() const
360 by Adam Reichold
manual merge of future branch
1052
{
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
1053
    return m_layout->layoutMode();
360 by Adam Reichold
manual merge of future branch
1054
}
1055
814 by Adam Reichold
move document view enumerations and print options to global header
1056
void DocumentView::setLayoutMode(LayoutMode layoutMode)
360 by Adam Reichold
manual merge of future branch
1057
{
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
1058
    if(m_layout->layoutMode() != layoutMode && layoutMode >= 0 && layoutMode < NumberOfLayoutModes)
360 by Adam Reichold
manual merge of future branch
1059
    {
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1060
        m_layout.reset(DocumentLayout::fromLayoutMode(layoutMode));
360 by Adam Reichold
manual merge of future branch
1061
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
1062
        if(m_currentPage != m_layout->currentPage(m_currentPage))
360 by Adam Reichold
manual merge of future branch
1063
        {
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
1064
            m_currentPage = m_layout->currentPage(m_currentPage);
360 by Adam Reichold
manual merge of future branch
1065
545 by Adam Reichold
merge currentPageChanged signals and improve setTwoPagesMode method
1066
            emit currentPageChanged(m_currentPage);
360 by Adam Reichold
manual merge of future branch
1067
        }
1068
1069
        prepareScene();
1070
        prepareView();
1071
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
1072
        emit layoutModeChanged(layoutMode);
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1073
1074
        s_settings->documentView().setLayoutMode(layoutMode);
360 by Adam Reichold
manual merge of future branch
1075
    }
1076
}
1077
1464.1.4 by Adam Reichold
Remove the static right-to-left setting since a user might switch document types frequently.
1078
void DocumentView::setRightToLeftMode(bool rightToLeftMode)
1079
{
1080
    if(m_rightToLeftMode != rightToLeftMode)
1081
    {
1082
        m_rightToLeftMode = rightToLeftMode;
1083
1084
        prepareScene();
1085
        prepareView();
1086
1087
        emit rightToLeftModeChanged(m_rightToLeftMode);
1472 by Adam Reichold
Use a weaker notion of defaulting to right-to-left on right-to-left locales to remove non-uniformity of handling settings.
1088
1089
        s_settings->documentView().setRightToLeftMode(m_rightToLeftMode);
1464.1.4 by Adam Reichold
Remove the static right-to-left setting since a user might switch document types frequently.
1090
    }
1091
}
1092
360 by Adam Reichold
manual merge of future branch
1093
void DocumentView::setScaleMode(ScaleMode scaleMode)
1094
{
738 by Adam Reichold
explicitly check for valid layout and scale mode enums and add default case to switch statements to be more robust against malformed configuration files
1095
    if(m_scaleMode != scaleMode && scaleMode >= 0 && scaleMode < NumberOfScaleModes)
360 by Adam Reichold
manual merge of future branch
1096
    {
1097
        m_scaleMode = scaleMode;
1098
372 by Adam Reichold
save left and top for return
1099
        qreal left = 0.0, top = 0.0;
1100
        saveLeftAndTop(left, top);
1101
1608 by Adam Reichold
Instead of always showing the vertical scroll bar for simpler visble area calculations, adjust the scroll bar policy based on the scale mode.
1102
        adjustScrollBarPolicy();
1103
360 by Adam Reichold
manual merge of future branch
1104
        prepareScene();
372 by Adam Reichold
save left and top for return
1105
        prepareView(left, top);
360 by Adam Reichold
manual merge of future branch
1106
1107
        emit scaleModeChanged(m_scaleMode);
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1108
1109
        s_settings->documentView().setScaleMode(m_scaleMode);
360 by Adam Reichold
manual merge of future branch
1110
    }
1111
}
1112
1113
void DocumentView::setScaleFactor(qreal scaleFactor)
1114
{
1580 by Adam Reichold
Make the minimum and maximum scale factors into hidden settings.
1115
    if(!qFuzzyCompare(m_scaleFactor, scaleFactor)
1116
            && scaleFactor >= s_settings->documentView().minimumScaleFactor()
1117
            && scaleFactor <= s_settings->documentView().maximumScaleFactor())
360 by Adam Reichold
manual merge of future branch
1118
    {
1119
        m_scaleFactor = scaleFactor;
1120
814 by Adam Reichold
move document view enumerations and print options to global header
1121
        if(m_scaleMode == ScaleFactorMode)
360 by Adam Reichold
manual merge of future branch
1122
        {
372 by Adam Reichold
save left and top for return
1123
            qreal left = 0.0, top = 0.0;
1124
            saveLeftAndTop(left, top);
1125
360 by Adam Reichold
manual merge of future branch
1126
            prepareScene();
372 by Adam Reichold
save left and top for return
1127
            prepareView(left, top);
360 by Adam Reichold
manual merge of future branch
1128
        }
1129
1130
        emit scaleFactorChanged(m_scaleFactor);
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1131
1132
        s_settings->documentView().setScaleFactor(m_scaleFactor);
360 by Adam Reichold
manual merge of future branch
1133
    }
1134
}
1135
813 by Adam Reichold
move page item enumerations into global header
1136
void DocumentView::setRotation(Rotation rotation)
360 by Adam Reichold
manual merge of future branch
1137
{
1126 by Adam Reichold
some minor code clean-ups
1138
    if(m_rotation != rotation && rotation >= 0 && rotation < NumberOfRotations)
360 by Adam Reichold
manual merge of future branch
1139
    {
1140
        m_rotation = rotation;
1141
1142
        prepareScene();
1143
        prepareView();
1144
1145
        emit rotationChanged(m_rotation);
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1146
1898.2.8 by Adam Reichold
Synchronize with parent branch.
1147
        s_settings->documentView().setRotation(m_rotation);
360 by Adam Reichold
manual merge of future branch
1148
    }
1898.1.7 by Adam Reichold
Serialize the render flags for restoring tabs and per-file settings.
1149
}
1150
1898.1.9 by Adam Reichold
Merge the RenderResolution and RenderParam structures.
1151
void DocumentView::setRenderFlags(qpdfview::RenderFlags renderFlags)
1898.1.7 by Adam Reichold
Serialize the render flags for restoring tabs and per-file settings.
1152
{
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1153
    if(m_renderFlags != renderFlags)
1154
    {
1898.2.14 by Adam Reichold
Give the render flag difference variables a more descriptive name.
1155
        const qpdfview::RenderFlags changedFlags = m_renderFlags ^ renderFlags;
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1156
1157
        m_renderFlags = renderFlags;
1158
1159
        qreal left = 0.0, top = 0.0;
1160
        saveLeftAndTop(left, top);
1161
1162
        prepareScene();
1163
        prepareView(left, top);
1164
1923.1.1 by Adam Reichold
Make it possible to dynamically adjust the thumbnail size w.r.t. to the first viewport they are visible in.
1165
        prepareThumbnailsScene();
1166
1898.2.14 by Adam Reichold
Give the render flag difference variables a more descriptive name.
1167
        if(changedFlags.testFlag(InvertColors))
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1168
        {
1169
            prepareBackground();
1170
1171
            emit invertColorsChanged(invertColors());
1172
1173
            s_settings->documentView().setInvertColors(invertColors());
1174
        }
2108.1.2 by Johan Björklund
Name change to "Invert lightness" and other fixes
1175
1176
        if(changedFlags.testFlag(InvertLightness))
2108.1.1 by Johan Björklund
Invert light
1177
        {
1178
            prepareBackground();
1179
2108.1.2 by Johan Björklund
Name change to "Invert lightness" and other fixes
1180
            emit invertLightnessChanged(invertLightness());
2108.1.1 by Johan Björklund
Invert light
1181
2108.1.2 by Johan Björklund
Name change to "Invert lightness" and other fixes
1182
            s_settings->documentView().setInvertLightness(invertLightness());
2108.1.1 by Johan Björklund
Invert light
1183
        }
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1184
1898.2.14 by Adam Reichold
Give the render flag difference variables a more descriptive name.
1185
        if(changedFlags.testFlag(ConvertToGrayscale))
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1186
        {
1187
            emit convertToGrayscaleChanged(convertToGrayscale());
1188
1189
            s_settings->documentView().setConvertToGrayscale(convertToGrayscale());
1190
        }
1191
1898.2.14 by Adam Reichold
Give the render flag difference variables a more descriptive name.
1192
        if(changedFlags.testFlag(TrimMargins))
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1193
        {
1194
            emit trimMarginsChanged(trimMargins());
1195
1196
            s_settings->documentView().setTrimMargins(trimMargins());
1197
        }
1198
1898.2.14 by Adam Reichold
Give the render flag difference variables a more descriptive name.
1199
        if(changedFlags.testFlag(DarkenWithPaperColor) || changedFlags.testFlag(LightenWithPaperColor))
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1200
        {
1201
            emit compositionModeChanged(compositionMode());
1202
1203
            s_settings->documentView().setCompositionMode(compositionMode());
1204
        }
1898.2.10 by Adam Reichold
Extend the presentation view to use render flags as well.
1205
1206
        emit renderFlagsChanged(m_renderFlags);
1898.2.6 by Adam Reichold
Extend the document view's render flags helper methods to consider the composition mode (hence it will also be stored in the database).
1207
    }
1898.1.7 by Adam Reichold
Serialize the render flags for restoring tabs and per-file settings.
1208
}
1209
1898.1.10 by Adam Reichold
Make the render parameters implicitly shared so that render tasks and their pages can share this which should reduce memory consumption for tiling.
1210
void DocumentView::setRenderFlag(qpdfview::RenderFlag renderFlag, bool enabled)
1211
{
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1212
    if(enabled)
1213
    {
1214
        setRenderFlags(m_renderFlags | renderFlag);
1215
    }
1216
    else
1217
    {
1218
        setRenderFlags(m_renderFlags & ~renderFlag);
1219
    }
1220
}
1221
1222
CompositionMode DocumentView::compositionMode() const
1223
{
1224
    if(m_renderFlags.testFlag(DarkenWithPaperColor))
1225
    {
1226
        return DarkenWithPaperColorMode;
1227
    }
1228
    else if(m_renderFlags.testFlag(LightenWithPaperColor))
1229
    {
1230
        return LightenWithPaperColorMode;
1231
    }
1232
    else
1233
    {
1234
        return DefaultCompositionMode;
1898.1.1 by Adam Reichold
Move the trim margins flag into the render parameters and make it a per-tab property.
1235
    }
1236
}
1237
1898.2.4 by Adam Reichold
Make the composition mode a per-tab property.
1238
void DocumentView::setCompositionMode(CompositionMode compositionMode)
1239
{
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1240
    switch(compositionMode)
1898.2.4 by Adam Reichold
Make the composition mode a per-tab property.
1241
    {
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1242
    default:
1243
    case DefaultCompositionMode:
1898.2.11 by Adam Reichold
Small optimization to the composition mode setter.
1244
        setRenderFlags((renderFlags() & ~DarkenWithPaperColor) & ~LightenWithPaperColor);
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1245
        break;
1246
    case DarkenWithPaperColorMode:
1898.2.11 by Adam Reichold
Small optimization to the composition mode setter.
1247
        setRenderFlags((renderFlags() | DarkenWithPaperColor) & ~LightenWithPaperColor);
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1248
        break;
1249
    case LightenWithPaperColorMode:
1898.2.11 by Adam Reichold
Small optimization to the composition mode setter.
1250
        setRenderFlags((renderFlags() & ~DarkenWithPaperColor) | LightenWithPaperColor);
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1251
        break;
1898.2.4 by Adam Reichold
Make the composition mode a per-tab property.
1252
    }
1253
}
1254
360 by Adam Reichold
manual merge of future branch
1255
void DocumentView::setHighlightAll(bool highlightAll)
1256
{
1257
    if(m_highlightAll != highlightAll)
1258
    {
1259
        m_highlightAll = highlightAll;
1260
1717.1.5 by Razi Alavizadeh
Track the current result of views and implement "find". (now using central search model)
1261
        if(m_highlightAll)
1717.1.4 by Razi Alavizadeh
Apply new highlightAll state (now using central search model).
1262
        {
1719 by Adam Reichold
Merge central search model.
1263
            for(int index = 0; index < m_pages.count(); ++index)
1264
            {
1265
                const QList< QRectF >& results = s_searchModel->resultsOnPage(this, index + 1);
1266
1267
                m_pageItems.at(index)->setHighlights(results);
1268
                m_thumbnailItems.at(index)->setHighlights(results);
1717.1.4 by Razi Alavizadeh
Apply new highlightAll state (now using central search model).
1269
            }
1270
        }
1271
        else
1272
        {
1719 by Adam Reichold
Merge central search model.
1273
            for(int index = 0; index < m_pages.count(); ++index)
1717.1.4 by Razi Alavizadeh
Apply new highlightAll state (now using central search model).
1274
            {
1275
                m_pageItems.at(index)->setHighlights(QList< QRectF >());
1276
                m_thumbnailItems.at(index)->setHighlights(QList< QRectF >());
1277
            }
1278
        }
360 by Adam Reichold
manual merge of future branch
1279
1280
        emit highlightAllChanged(m_highlightAll);
1410 by Adam Reichold
Move handling of document view settings back into document view itself since embeddability is not a concern anymore.
1281
1282
        s_settings->documentView().setHighlightAll(highlightAll);
360 by Adam Reichold
manual merge of future branch
1283
    }
1284
}
1285
813 by Adam Reichold
move page item enumerations into global header
1286
void DocumentView::setRubberBandMode(RubberBandMode rubberBandMode)
515 by Adam Reichold
enable waiting for rubber band indicated by main window interaction
1287
{
901.1.1 by Alexander Volkov
fix range checking for rubberBandMode
1288
    if(m_rubberBandMode != rubberBandMode && rubberBandMode >= 0 && rubberBandMode < NumberOfRubberBandModes)
515 by Adam Reichold
enable waiting for rubber band indicated by main window interaction
1289
    {
566 by Adam Reichold
handle rubber band mode as document view property and simplify highlight all handling
1290
        m_rubberBandMode = rubberBandMode;
1291
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
1292
        foreach(PageItem* page, m_pageItems)
566 by Adam Reichold
handle rubber band mode as document view property and simplify highlight all handling
1293
        {
1294
            page->setRubberBandMode(m_rubberBandMode);
1295
        }
1296
1297
        emit rubberBandModeChanged(m_rubberBandMode);
515 by Adam Reichold
enable waiting for rubber band indicated by main window interaction
1298
    }
1299
}
1300
2041.2.12 by Adam Reichold
Fix usage of QList in the bookmark and search models and various small performance issues reported by the clazy tool using the checks of "level0,level1,level2,no-missing-qobject-macro,no-qstring-allocations,no-copyable-polymorphic,no-ctor-missing-parent-argument,no-reserve-candidates".
1301
void DocumentView::setThumbnailsViewportSize(QSize thumbnailsViewportSize)
1923.1.1 by Adam Reichold
Make it possible to dynamically adjust the thumbnail size w.r.t. to the first viewport they are visible in.
1302
{
1923.1.4 by Adam Reichold
Communicate the thumbnails viewport size via an explicit property to have more flexibility in the future to decide which viewport determines scaling.
1303
    if(m_thumbnailsViewportSize != thumbnailsViewportSize)
1923.1.1 by Adam Reichold
Make it possible to dynamically adjust the thumbnail size w.r.t. to the first viewport they are visible in.
1304
    {
1923.1.4 by Adam Reichold
Communicate the thumbnails viewport size via an explicit property to have more flexibility in the future to decide which viewport determines scaling.
1305
        m_thumbnailsViewportSize = thumbnailsViewportSize;
1306
1923.1.1 by Adam Reichold
Make it possible to dynamically adjust the thumbnail size w.r.t. to the first viewport they are visible in.
1307
        prepareThumbnailsScene();
1308
    }
1309
}
1310
1209 by Adam Reichold
make thumbnails layout orientation adjust according to dock orientation
1311
void DocumentView::setThumbnailsOrientation(Qt::Orientation thumbnailsOrientation)
1312
{
1313
    if(m_thumbnailsOrientation != thumbnailsOrientation)
1314
    {
1315
        m_thumbnailsOrientation = thumbnailsOrientation;
1316
1317
        prepareThumbnailsScene();
1318
    }
1319
}
1320
2060 by Adam Reichold
Extend the database schema to store the paths currently expanded in the outline view.
1321
QSet< QByteArray > DocumentView::saveExpandedPaths() const
1322
{
1323
    QSet< QByteArray > expandedPaths;
1324
1325
    ::saveExpandedPaths(m_outlineModel.data(), expandedPaths);
1326
1327
    return expandedPaths;
2059.1.1 by angelforest
Save and restore expanded state of outline nodes for each file.
1328
}
2060 by Adam Reichold
Extend the database schema to store the paths currently expanded in the outline view.
1329
1330
void DocumentView::restoreExpandedPaths(const QSet< QByteArray >& expandedPaths)
1331
{
1332
    ::restoreExpandedPaths(m_outlineModel.data(), expandedPaths);
2059.1.1 by angelforest
Save and restore expanded state of outline nodes for each file.
1333
}
1334
1994 by Adam Reichold
Use domain-specific data structures instead of standard item models to handle outline and properties.
1335
QAbstractItemModel* DocumentView::fontsModel() const
360 by Adam Reichold
manual merge of future branch
1336
{
2040 by Adam Reichold
Improve naming consistency in the model accessor methods.
1337
    return m_document->fonts();
360 by Adam Reichold
manual merge of future branch
1338
}
1339
1930 by Adam Reichold
Do some minor code clean ups.
1340
bool DocumentView::searchWasCanceled() const
1341
{
1342
    return m_searchTask->wasCanceled();
1343
}
1344
1345
int DocumentView::searchProgress() const
1346
{
1347
    return m_searchTask->progress();
1348
}
1349
1740 by Adam Reichold
Merge displaying surrounding text in extended search model.
1350
QString DocumentView::searchText() const
1351
{
1352
    return m_searchTask->text();
1353
}
1354
1355
bool DocumentView::searchMatchCase() const
1356
{
1357
    return m_searchTask->matchCase();
1358
}
1359
1824 by Adam Reichold
Add a partial implementation of a whole-words search option currently respected only by the DjVu backend.
1360
bool DocumentView::searchWholeWords() const
1361
{
1362
    return m_searchTask->wholeWords();
1363
}
1364
1839 by Adam Reichold
Try to decouple highlighted matched text from the matching itself done by the backends.
1365
QPair< QString, QString > DocumentView::searchContext(int page, const QRectF& rect) const
1734.1.1 by Razi Alavizadeh
Extract surrounding text of search results.
1366
{
1742.1.6 by Adam Reichold
Make the surrounding text interface page-based to improve API consistency.
1367
    if(page < 1 || page > m_pages.size() || rect.isEmpty())
1734.1.1 by Razi Alavizadeh
Extract surrounding text of search results.
1368
    {
1839 by Adam Reichold
Try to decouple highlighted matched text from the matching itself done by the backends.
1369
        return qMakePair(QString(), QString());
1734.1.1 by Razi Alavizadeh
Extract surrounding text of search results.
1370
    }
1371
1740 by Adam Reichold
Merge displaying surrounding text in extended search model.
1372
    // Fetch at most half of a line as centered on the given rectangle as possible.
1742.1.6 by Adam Reichold
Make the surrounding text interface page-based to improve API consistency.
1373
    const qreal pageWidth = m_pages.at(page - 1)->size().width();
1777 by Adam Reichold
Fix a compilation issue on ARM architecture due to 'qreal' being 'float' there.
1374
    const qreal width = qMax(rect.width(), pageWidth / qreal(2));
1375
    const qreal x = qBound(qreal(0), rect.x() + rect.width() / qreal(2) - width / qreal(2), pageWidth - width);
1740 by Adam Reichold
Merge displaying surrounding text in extended search model.
1376
1377
    const QRectF surroundingRect(x, rect.top(), width, rect.height());
1378
1845.1.1 by Adam Reichold
Add a method for cached text extraction and make use of it in the extended search dock.
1379
    const QString& matchedText = m_pages.at(page - 1)->cachedText(rect);
1380
    const QString& surroundingText = m_pages.at(page - 1)->cachedText(surroundingRect);
1839 by Adam Reichold
Try to decouple highlighted matched text from the matching itself done by the backends.
1381
1382
    return qMakePair(matchedText, surroundingText);
1734.1.1 by Razi Alavizadeh
Extract surrounding text of search results.
1383
}
1384
2055 by Adam Reichold
Update the search line edit content on tab change if the current tab has any results.
1385
bool DocumentView::hasSearchResults()
1386
{
1387
    return s_searchModel->hasResults(this);
1388
}
1389
1981 by Adam Reichold
Add support for outline links to external files.
1390
QString DocumentView::resolveFileName(QString fileName) const
1391
{
1392
    if(QFileInfo(fileName).isRelative())
1393
    {
1394
        fileName = m_fileInfo.dir().filePath(fileName);
1395
    }
1396
1397
    return fileName;
1398
}
1399
1400
QUrl DocumentView::resolveUrl(QUrl url) const
1401
{
1402
    const QString path = url.path();
1403
1404
    if(url.isRelative() && QFileInfo(path).isRelative())
1405
    {
1406
        url.setPath(m_fileInfo.dir().filePath(path));
1407
    }
1408
1409
    return url;
1410
}
1411
2041.2.12 by Adam Reichold
Fix usage of QList in the bookmark and search models and various small performance issues reported by the clazy tool using the checks of "level0,level1,level2,no-missing-qobject-macro,no-qstring-allocations,no-copyable-polymorphic,no-ctor-missing-parent-argument,no-reserve-candidates".
1412
DocumentView::SourceLink DocumentView::sourceLink(QPoint pos)
1951 by Adam Reichold
Make the SyncTeX source link accessible via the main window context menu since it has better discoverability and is harder to trigger accidentally.
1413
{
1414
    SourceLink sourceLink;
1415
1416
#ifdef WITH_SYNCTEX
1417
1418
    if(const PageItem* page = dynamic_cast< PageItem* >(itemAt(pos)))
1419
    {
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
1420
        const int sourcePage = page->index() + 1;
1421
        const QPointF sourcePos = page->sourcePos(page->mapFromScene(mapToScene(pos)));
1422
1423
        sourceLink = scanForSourceLink(m_fileInfo.absoluteFilePath(), sourcePage, sourcePos);
1951 by Adam Reichold
Make the SyncTeX source link accessible via the main window context menu since it has better discoverability and is harder to trigger accidentally.
1424
    }
1425
1426
#else
1427
1428
    Q_UNUSED(pos);
1429
1430
#endif // WITH_SYNCTEX
1431
1432
    return sourceLink;
1433
}
1434
1435
void DocumentView::openInSourceEditor(const DocumentView::SourceLink& sourceLink)
1436
{
1954 by Adam Reichold
Improve SyncTeX discoverability some more by showing the menu entry even if no source editor was configured.
1437
    if(!s_settings->documentView().sourceEditor().isEmpty())
1438
    {
1439
        const QString absoluteFilePath = m_fileInfo.dir().absoluteFilePath(sourceLink.name);
1440
        const QString sourceEditorCommand = s_settings->documentView().sourceEditor().arg(absoluteFilePath, QString::number(sourceLink.line), QString::number(sourceLink.column));
1951 by Adam Reichold
Make the SyncTeX source link accessible via the main window context menu since it has better discoverability and is harder to trigger accidentally.
1441
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
1442
        startDetached(sourceEditorCommand);
1954 by Adam Reichold
Improve SyncTeX discoverability some more by showing the menu entry even if no source editor was configured.
1443
    }
1444
    else
1445
    {
1446
        QMessageBox::information(this, tr("Information"), tr("The source editor has not been set."));
1447
    }
1951 by Adam Reichold
Make the SyncTeX source link accessible via the main window context menu since it has better discoverability and is harder to trigger accidentally.
1448
}
1449
444 by Adam Reichold
change handling of show events to keep position on tab change
1450
void DocumentView::show()
1451
{
1452
    QGraphicsView::show();
1453
1454
    prepareView();
1455
}
1456
360 by Adam Reichold
manual merge of future branch
1457
bool DocumentView::open(const QString& filePath)
1458
{
1521 by Adam Reichold
Follow Qt Creator style guide and use capital letter for namespaces and refactor Djvu link loading code.
1459
    Model::Document* document = PluginHandler::instance()->loadDocument(filePath);
360 by Adam Reichold
manual merge of future branch
1460
1461
    if(document != 0)
1462
    {
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
1463
        QVector< Model::Page* > pages;
1464
1465
        if(!checkDocument(filePath, document, pages))
360 by Adam Reichold
manual merge of future branch
1466
        {
1470 by Adam Reichold
We did never support documents with zero pages, so check for that.
1467
            delete document;
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
1468
            qDeleteAll(pages);
1469
1470 by Adam Reichold
We did never support documents with zero pages, so check for that.
1470
            return false;
360 by Adam Reichold
manual merge of future branch
1471
        }
1472
1413 by Adam Reichold
Store a QFileInfo instead of a plain path in the document view to reduce the number of temporary objects.
1473
        m_fileInfo.setFile(filePath);
1474
        m_wasModified = false;
1475
360 by Adam Reichold
manual merge of future branch
1476
        m_currentPage = 1;
372 by Adam Reichold
save left and top for return
1477
1046.1.48 by Adam Reichold
enhance history mechanism for jumping backward and forward
1478
        m_past.clear();
1479
        m_future.clear();
360 by Adam Reichold
manual merge of future branch
1480
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
1481
        prepareDocument(document, pages);
360 by Adam Reichold
manual merge of future branch
1482
1473 by Adam Reichold
Add interface to load document-supplied defaults which will overwrite per-tab settings but will be overwritten by per-file settings.
1483
        loadDocumentDefaults();
1484
1649 by Adam Reichold
We might also need to adjust the scroll bar policy after loading document defaults.
1485
        adjustScrollBarPolicy();
1486
1490 by Adam Reichold
Do not call public setter from loadDocumentDefaults as this would emit unwanted signals and call prepareScene.
1487
        prepareScene();
1488
        prepareView();
1489
1490
        prepareThumbnailsScene();
1491
1238 by Adam Reichold
introduce a signal for document change to definitely setup the model header for outline and properties
1492
        emit documentChanged();
1493
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
1494
        emit numberOfPagesChanged(m_pages.count());
360 by Adam Reichold
manual merge of future branch
1495
        emit currentPageChanged(m_currentPage);
1046.1.53 by Adam Reichold
track history status using a dedicated signal and better align keyboard shortcuts
1496
1497
        emit canJumpChanged(false, false);
1648 by Adam Reichold
Loading document defaults might change the view mode so we have to emit the corresponding signals.
1498
1499
        emit continuousModeChanged(m_continuousMode);
1500
        emit layoutModeChanged(m_layout->layoutMode());
1501
        emit rightToLeftModeChanged(m_rightToLeftMode);
360 by Adam Reichold
manual merge of future branch
1502
    }
1503
1504
    return document != 0;
1505
}
1506
1507
bool DocumentView::refresh()
1508
{
1521 by Adam Reichold
Follow Qt Creator style guide and use capital letter for namespaces and refactor Djvu link loading code.
1509
    Model::Document* document = PluginHandler::instance()->loadDocument(m_fileInfo.filePath());
360 by Adam Reichold
manual merge of future branch
1510
1511
    if(document != 0)
1512
    {
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
1513
        QVector< Model::Page* > pages;
1514
1515
        if(!checkDocument(m_fileInfo.filePath(), document, pages))
360 by Adam Reichold
manual merge of future branch
1516
        {
1470 by Adam Reichold
We did never support documents with zero pages, so check for that.
1517
            delete document;
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
1518
            qDeleteAll(pages);
1519
1470 by Adam Reichold
We did never support documents with zero pages, so check for that.
1520
            return false;
360 by Adam Reichold
manual merge of future branch
1521
        }
1522
372 by Adam Reichold
save left and top for return
1523
        qreal left = 0.0, top = 0.0;
1524
        saveLeftAndTop(left, top);
366 by Adam Reichold
add prefetch and make culling thread-safe
1525
1413 by Adam Reichold
Store a QFileInfo instead of a plain path in the document view to reduce the number of temporary objects.
1526
        m_wasModified = false;
1527
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
1528
        m_currentPage = qMin(m_currentPage, document->numberOfPages());
372 by Adam Reichold
save left and top for return
1529
2059.1.2 by angelforest
Save outline state as byte arrays in separate table
1530
        QSet< QByteArray > expandedPaths;
2060 by Adam Reichold
Extend the database schema to store the paths currently expanded in the outline view.
1531
        ::saveExpandedPaths(m_outlineModel.data(), expandedPaths);
1803.1.1 by Adam Reichold
Restore expanded paths within outline after refreshing document.
1532
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
1533
        prepareDocument(document, pages);
360 by Adam Reichold
manual merge of future branch
1534
2060 by Adam Reichold
Extend the database schema to store the paths currently expanded in the outline view.
1535
        ::restoreExpandedPaths(m_outlineModel.data(), expandedPaths);
1803.1.1 by Adam Reichold
Restore expanded paths within outline after refreshing document.
1536
372 by Adam Reichold
save left and top for return
1537
        prepareScene();
1538
        prepareView(left, top);
1539
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
1540
        prepareThumbnailsScene();
1541
1238 by Adam Reichold
introduce a signal for document change to definitely setup the model header for outline and properties
1542
        emit documentChanged();
1543
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
1544
        emit numberOfPagesChanged(m_pages.count());
360 by Adam Reichold
manual merge of future branch
1545
        emit currentPageChanged(m_currentPage);
1546
    }
1547
1548
    return document != 0;
1549
}
1550
726.1.1 by Adam Reichold
separate 'save copy' (without changes) and 'save as' (with changes) actions
1551
bool DocumentView::save(const QString& filePath, bool withChanges)
360 by Adam Reichold
manual merge of future branch
1552
{
1893 by Adam Reichold
Try to fix the pointless nesting within the document view's save method.
1553
    // Save document to temporary file...
1926 by Adam Reichold
Small clean up of error handling in print methods.
1554
    QTemporaryFile temporaryFile;
1555
1927.1.5 by Adam Reichold
Add support to save images using Qt's built-in formats.
1556
    adjustFileTemplateSuffix(temporaryFile, QFileInfo(filePath).suffix());
1557
1893 by Adam Reichold
Try to fix the pointless nesting within the document view's save method.
1558
    if(!temporaryFile.open())
1559
    {
1560
        return false;
1561
    }
1562
1563
    temporaryFile.close();
1564
1565
    if(!m_document->save(temporaryFile.fileName(), withChanges))
1566
    {
1567
        return false;
1568
    }
1569
1570
    // Copy from temporary file to actual file...
1926 by Adam Reichold
Small clean up of error handling in print methods.
1571
    QFile file(filePath);
1572
1894 by Adam Reichold
Move the actual file copying into a helper function.
1573
    if(!temporaryFile.open())
1574
    {
1575
        return false;
1576
    }
1003 by Adam Reichold
always use the same caution when saving files since paths can be
1577
1893 by Adam Reichold
Try to fix the pointless nesting within the document view's save method.
1578
    if(!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
1579
    {
1580
        return false;
1581
    }
1582
1894 by Adam Reichold
Move the actual file copying into a helper function.
1583
    if(!copyFile(temporaryFile, file))
1893 by Adam Reichold
Try to fix the pointless nesting within the document view's save method.
1584
    {
1894 by Adam Reichold
Move the actual file copying into a helper function.
1585
        return false;
1003 by Adam Reichold
always use the same caution when saving files since paths can be
1586
    }
1893 by Adam Reichold
Try to fix the pointless nesting within the document view's save method.
1587
1588
    if(withChanges)
1589
    {
1590
        m_wasModified = false;
1591
    }
1592
1593
    return true;
360 by Adam Reichold
manual merge of future branch
1594
}
1595
644.1.1 by Adam Reichold
initial implementation of extended print options
1596
bool DocumentView::print(QPrinter* printer, const PrintOptions& printOptions)
1575.1.1 by Martin Spacek
Make zoom steps logarithmic by making zoomBy a multiple or fraction of the previous zoom factor
1597
{
1147 by Adam Reichold
begin to make local variables immutable by default
1598
    const int fromPage = printer->fromPage() != 0 ? printer->fromPage() : 1;
1599
    const int toPage = printer->toPage() != 0 ? printer->toPage() : m_pages.count();
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
1600
360 by Adam Reichold
manual merge of future branch
1601
#ifdef WITH_CUPS
1602
1046.1.30 by Adam Reichold
merge model header and source and remove some redundant includes
1603
    if(m_document->canBePrintedUsingCUPS())
360 by Adam Reichold
manual merge of future branch
1604
    {
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
1605
        return printUsingCUPS(printer, printOptions, fromPage, toPage);
826 by Adam Reichold
improve format awareness of the UI in a few places
1606
    }
1607
1608
#endif // WITH_CUPS
360 by Adam Reichold
manual merge of future branch
1609
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
1610
    return printUsingQt(printer, printOptions, fromPage, toPage);
360 by Adam Reichold
manual merge of future branch
1611
}
1612
1613
void DocumentView::previousPage()
1614
{
2109 by Adam Reichold
Add relative-jumps setting to enable forcibly jump to the beginning of a page.
1615
    const qreal leftAndTop = s_settings->documentView().relativeJumps() ? qQNaN() : 0.0;
1616
1617
    jumpToPage(m_layout->previousPage(m_currentPage), true, leftAndTop, leftAndTop);
360 by Adam Reichold
manual merge of future branch
1618
}
1619
1620
void DocumentView::nextPage()
1621
{
2109 by Adam Reichold
Add relative-jumps setting to enable forcibly jump to the beginning of a page.
1622
    const qreal leftAndTop = s_settings->documentView().relativeJumps() ? qQNaN() : 0.0;
1623
1624
    jumpToPage(m_layout->nextPage(m_currentPage, m_pages.count()), true, leftAndTop, leftAndTop);
360 by Adam Reichold
manual merge of future branch
1625
}
1626
1627
void DocumentView::firstPage()
1628
{
2109 by Adam Reichold
Add relative-jumps setting to enable forcibly jump to the beginning of a page.
1629
    const qreal leftAndTop = s_settings->documentView().relativeJumps() ? qQNaN() : 0.0;
1630
1631
    jumpToPage(1, true, leftAndTop, leftAndTop);
360 by Adam Reichold
manual merge of future branch
1632
}
1633
1634
void DocumentView::lastPage()
1635
{
2109 by Adam Reichold
Add relative-jumps setting to enable forcibly jump to the beginning of a page.
1636
    const qreal leftAndTop = s_settings->documentView().relativeJumps() ? qQNaN() : 0.0;
1637
1638
    jumpToPage(m_pages.count(), leftAndTop, leftAndTop);
360 by Adam Reichold
manual merge of future branch
1639
}
1640
1881.1.2 by Adam Reichold
Use quiet NaN as default value for page-relative positions instead of explicit flag for more flexibility to indicate optional position changes.
1641
void DocumentView::jumpToPage(int page, bool trackChange, qreal newLeft, qreal newTop)
360 by Adam Reichold
manual merge of future branch
1642
{
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
1643
    if(page >= 1 && page <= m_pages.count())
360 by Adam Reichold
manual merge of future branch
1644
    {
485 by Adam Reichold
actually compare left/top with changeLeft/Top in jumpToPage
1645
        qreal left = 0.0, top = 0.0;
1646
        saveLeftAndTop(left, top);
1647
1881.1.2 by Adam Reichold
Use quiet NaN as default value for page-relative positions instead of explicit flag for more flexibility to indicate optional position changes.
1648
        if(qIsNaN(newLeft))
1881.1.1 by Adam Reichold
Try to keep relative page position when jumping to a new location without explicit page-relative coordinates.
1649
        {
1899 by Adam Reichold
Fix a subtle issue of scroll-if-not-visible, i.e. keeping the page-relative position larger than 1.0 can mean we never scroll at all.
1650
            newLeft = qBound(qreal(0.0), left, qreal(1.0));
1881.1.2 by Adam Reichold
Use quiet NaN as default value for page-relative positions instead of explicit flag for more flexibility to indicate optional position changes.
1651
        }
1652
1653
        if(qIsNaN(newTop))
1654
        {
1899 by Adam Reichold
Fix a subtle issue of scroll-if-not-visible, i.e. keeping the page-relative position larger than 1.0 can mean we never scroll at all.
1655
            newTop = qBound(qreal(0.0), top, qreal(1.0));
1881.1.1 by Adam Reichold
Try to keep relative page position when jumping to a new location without explicit page-relative coordinates.
1656
        }
1657
1658
        if(m_currentPage != m_layout->currentPage(page) || qAbs(left - newLeft) > 0.01 || qAbs(top - newTop) > 0.01)
486 by Adam Reichold
fix a unwanted interaction with the current page spin box signals and improve the coding style of jumpToPage
1659
        {
1046.1.48 by Adam Reichold
enhance history mechanism for jumping backward and forward
1660
            if(trackChange)
486 by Adam Reichold
fix a unwanted interaction with the current page spin box signals and improve the coding style of jumpToPage
1661
            {
1046.1.48 by Adam Reichold
enhance history mechanism for jumping backward and forward
1662
                m_past.append(Position(m_currentPage, left, top));
1046.1.52 by Adam Reichold
don't forget to clear the future upon history independent jumps
1663
                m_future.clear();
1046.1.53 by Adam Reichold
track history status using a dedicated signal and better align keyboard shortcuts
1664
1665
                emit canJumpChanged(true, false);
486 by Adam Reichold
fix a unwanted interaction with the current page spin box signals and improve the coding style of jumpToPage
1666
            }
1667
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
1668
            m_currentPage = m_layout->currentPage(page);
486 by Adam Reichold
fix a unwanted interaction with the current page spin box signals and improve the coding style of jumpToPage
1669
1881.1.10 by Adam Reichold
Add another flag to view preparation with indicates whether we force scrolling to resolve interactions between scroll-if-not-visible and trim-margins functions.
1670
            prepareView(newLeft, newTop, false, page);
486 by Adam Reichold
fix a unwanted interaction with the current page spin box signals and improve the coding style of jumpToPage
1671
1046.1.48 by Adam Reichold
enhance history mechanism for jumping backward and forward
1672
            emit currentPageChanged(m_currentPage, trackChange);
360 by Adam Reichold
manual merge of future branch
1673
        }
1674
    }
1675
}
1676
1046.1.48 by Adam Reichold
enhance history mechanism for jumping backward and forward
1677
bool DocumentView::canJumpBackward() const
1678
{
1679
    return !m_past.isEmpty();
1680
}
1681
1682
void DocumentView::jumpBackward()
1683
{
1684
    if(!m_past.isEmpty())
1685
    {
1686
        qreal left = 0.0, top = 0.0;
1687
        saveLeftAndTop(left, top);
1688
1076 by Adam Reichold
update online help and revert dropping of ineffective jumps from history
1689
        m_future.prepend(Position(m_currentPage, left, top));
1073 by Adam Reichold
don't store empty jumps in the history
1690
1147 by Adam Reichold
begin to make local variables immutable by default
1691
        const Position pos = m_past.takeLast();
1881.1.2 by Adam Reichold
Use quiet NaN as default value for page-relative positions instead of explicit flag for more flexibility to indicate optional position changes.
1692
        jumpToPage(pos.page, false, pos.left, pos.top);
1046.1.53 by Adam Reichold
track history status using a dedicated signal and better align keyboard shortcuts
1693
1694
        emit canJumpChanged(!m_past.isEmpty(), !m_future.isEmpty());
1046.1.48 by Adam Reichold
enhance history mechanism for jumping backward and forward
1695
    }
1696
}
1697
1698
bool DocumentView::canJumpForward() const
1699
{
1700
    return !m_future.isEmpty();
1701
}
1702
1703
void DocumentView::jumpForward()
1704
{
1705
    if(!m_future.isEmpty())
1706
    {
1707
        qreal left = 0.0, top = 0.0;
1708
        saveLeftAndTop(left, top);
1709
1076 by Adam Reichold
update online help and revert dropping of ineffective jumps from history
1710
        m_past.append(Position(m_currentPage, left, top));
1073 by Adam Reichold
don't store empty jumps in the history
1711
1147 by Adam Reichold
begin to make local variables immutable by default
1712
        const Position pos = m_future.takeFirst();
1881.1.2 by Adam Reichold
Use quiet NaN as default value for page-relative positions instead of explicit flag for more flexibility to indicate optional position changes.
1713
        jumpToPage(pos.page, false, pos.left, pos.top);
1046.1.53 by Adam Reichold
track history status using a dedicated signal and better align keyboard shortcuts
1714
1715
        emit canJumpChanged(!m_past.isEmpty(), !m_future.isEmpty());
1046.1.48 by Adam Reichold
enhance history mechanism for jumping backward and forward
1716
    }
1717
}
1718
1165 by Adam Reichold
always put temporary highlights on the exact page requests, not
1719
void DocumentView::temporaryHighlight(int page, const QRectF& highlight)
588 by Adam Reichold
add SyncTeX support
1720
{
1165 by Adam Reichold
always put temporary highlights on the exact page requests, not
1721
    if(page >= 1 && page <= m_pages.count() && !highlight.isNull())
1722
    {
1723
        prepareHighlight(page - 1, highlight);
1162 by Adam Reichold
use document view highlight instead of page item highlights for SyncTeX forward search, so that highlight all coninues to work if a search was conducted
1724
1165 by Adam Reichold
always put temporary highlights on the exact page requests, not
1725
        QTimer::singleShot(s_settings->documentView().highlightDuration(), this, SLOT(on_temporaryHighlight_timeout()));
1726
    }
588 by Adam Reichold
add SyncTeX support
1727
}
1728
1824 by Adam Reichold
Add a partial implementation of a whole-words search option currently respected only by the DjVu backend.
1729
void DocumentView::startSearch(const QString& text, bool matchCase, bool wholeWords)
360 by Adam Reichold
manual merge of future branch
1730
{
1731
    cancelSearch();
1778 by Adam Reichold
Provide separate slots for search cancellation and clearing of search results.
1732
    clearResults();
360 by Adam Reichold
manual merge of future branch
1733
2032 by Adam Reichold
Wire up parallel search execution via the settings dialog.
1734
    m_searchTask->start(m_pages, text, matchCase, wholeWords, m_currentPage, s_settings->documentView().parallelSearchExecution());
360 by Adam Reichold
manual merge of future branch
1735
}
1736
1719 by Adam Reichold
Merge central search model.
1737
void DocumentView::cancelSearch()
360 by Adam Reichold
manual merge of future branch
1738
{
1778 by Adam Reichold
Provide separate slots for search cancellation and clearing of search results.
1739
    m_searchTask->cancel();
1740
    m_searchTask->wait();
1741
}
1742
1743
void DocumentView::clearResults()
1744
{
1745
    s_searchModel->clearResults(this);
1746
1747
    m_currentResult = QModelIndex();
1748
1749
    m_highlight->setVisible(false);
1717.1.2 by Razi Alavizadeh
Add a central search model to store search results.
1750
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
1751
    foreach(PageItem* page, m_pageItems)
360 by Adam Reichold
manual merge of future branch
1752
    {
1162 by Adam Reichold
use document view highlight instead of page item highlights for SyncTeX forward search, so that highlight all coninues to work if a search was conducted
1753
        page->setHighlights(QList< QRectF >());
360 by Adam Reichold
manual merge of future branch
1754
    }
1755
1713 by Adam Reichold
Just update the thumbnail text instead of reconstruction.
1756
    foreach(ThumbnailItem* page, m_thumbnailItems)
1046.1.10 by Adam Reichold
display result highlights on thumbnails as well
1757
    {
1162 by Adam Reichold
use document view highlight instead of page item highlights for SyncTeX forward search, so that highlight all coninues to work if a search was conducted
1758
        page->setHighlights(QList< QRectF >());
1046.1.10 by Adam Reichold
display result highlights on thumbnails as well
1759
    }
1760
1716 by Adam Reichold
Use a flag in the invisible root item to determine whether an outline is automatically generated fallback outline.
1761
    if(s_settings->documentView().limitThumbnailsToResults())
1762
    {
1763
        prepareThumbnailsScene();
1764
    }
360 by Adam Reichold
manual merge of future branch
1765
}
1766
1719 by Adam Reichold
Merge central search model.
1767
void DocumentView::findPrevious()
1768
{
1720 by Adam Reichold
Factor out some redundant code from the find slots of the document view.
1769
    checkResult();
1719 by Adam Reichold
Merge central search model.
1770
1771
    m_currentResult = s_searchModel->findResult(this, m_currentResult, m_currentPage, SearchModel::FindPrevious);
1772
1720 by Adam Reichold
Factor out some redundant code from the find slots of the document view.
1773
    applyResult();
1719 by Adam Reichold
Merge central search model.
1774
}
1775
1776
void DocumentView::findNext()
1777
{
1720 by Adam Reichold
Factor out some redundant code from the find slots of the document view.
1778
    checkResult();
1719 by Adam Reichold
Merge central search model.
1779
1780
    m_currentResult = s_searchModel->findResult(this, m_currentResult, m_currentPage, SearchModel::FindNext);
1781
1720 by Adam Reichold
Factor out some redundant code from the find slots of the document view.
1782
    applyResult();
1717.1.5 by Razi Alavizadeh
Track the current result of views and implement "find". (now using central search model)
1783
}
1784
1727 by Adam Reichold
Implement jump to click search result via extended dock.
1785
void DocumentView::findResult(const QModelIndex& index)
1786
{
1787
    const int page = pageOfResult(index);
1788
    const QRectF rect = rectOfResult(index);
1789
1790
    if(page >= 1 && page <= m_pages.count() && !rect.isEmpty())
1791
    {
1792
        m_currentResult = index;
1793
1794
        applyResult();
1795
    }
1796
}
1797
360 by Adam Reichold
manual merge of future branch
1798
void DocumentView::zoomIn()
1799
{
814 by Adam Reichold
move document view enumerations and print options to global header
1800
    if(scaleMode() != ScaleFactorMode)
360 by Adam Reichold
manual merge of future branch
1801
    {
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1802
        const qreal currentScaleFactor = m_pageItems.at(m_currentPage - 1)->renderParam().scaleFactor();
1803
1804
        setScaleFactor(qMin(currentScaleFactor * s_settings->documentView().zoomFactor(),
1580 by Adam Reichold
Make the minimum and maximum scale factors into hidden settings.
1805
                            s_settings->documentView().maximumScaleFactor()));
1806
814 by Adam Reichold
move document view enumerations and print options to global header
1807
        setScaleMode(ScaleFactorMode);
360 by Adam Reichold
manual merge of future branch
1808
    }
1809
    else
1810
    {
1581 by Adam Reichold
Make zoom factor into a proper setting accessible via the settings dialog.
1811
        setScaleFactor(qMin(m_scaleFactor * s_settings->documentView().zoomFactor(),
1580 by Adam Reichold
Make the minimum and maximum scale factors into hidden settings.
1812
                            s_settings->documentView().maximumScaleFactor()));
360 by Adam Reichold
manual merge of future branch
1813
    }
1814
}
1815
1816
void DocumentView::zoomOut()
1817
{
814 by Adam Reichold
move document view enumerations and print options to global header
1818
    if(scaleMode() != ScaleFactorMode)
360 by Adam Reichold
manual merge of future branch
1819
    {
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
1820
        const qreal currentScaleFactor = m_pageItems.at(m_currentPage - 1)->renderParam().scaleFactor();
1821
1822
        setScaleFactor(qMax(currentScaleFactor / s_settings->documentView().zoomFactor(),
1580 by Adam Reichold
Make the minimum and maximum scale factors into hidden settings.
1823
                            s_settings->documentView().minimumScaleFactor()));
1824
814 by Adam Reichold
move document view enumerations and print options to global header
1825
        setScaleMode(ScaleFactorMode);
360 by Adam Reichold
manual merge of future branch
1826
    }
1827
    else
1828
    {
1581 by Adam Reichold
Make zoom factor into a proper setting accessible via the settings dialog.
1829
        setScaleFactor(qMax(m_scaleFactor / s_settings->documentView().zoomFactor(),
1580 by Adam Reichold
Make the minimum and maximum scale factors into hidden settings.
1830
                            s_settings->documentView().minimumScaleFactor()));
360 by Adam Reichold
manual merge of future branch
1831
    }
1832
}
1833
1834
void DocumentView::originalSize()
1835
{
1836
    setScaleFactor(1.0);
814 by Adam Reichold
move document view enumerations and print options to global header
1837
    setScaleMode(ScaleFactorMode);
360 by Adam Reichold
manual merge of future branch
1838
}
1839
1840
void DocumentView::rotateLeft()
1841
{
953 by Adam Reichold
results of a first glancing review preparing for the next beta release
1842
    switch(m_rotation)
360 by Adam Reichold
manual merge of future branch
1843
    {
813 by Adam Reichold
move page item enumerations into global header
1844
    default:
818 by Adam Reichold
move print options into separate header and rename rotation enum slightly
1845
    case RotateBy0:
813 by Adam Reichold
move page item enumerations into global header
1846
        setRotation(RotateBy270);
1847
        break;
1848
    case RotateBy90:
818 by Adam Reichold
move print options into separate header and rename rotation enum slightly
1849
        setRotation(RotateBy0);
813 by Adam Reichold
move page item enumerations into global header
1850
        break;
1851
    case RotateBy180:
1852
        setRotation(RotateBy90);
1853
        break;
1854
    case RotateBy270:
1855
        setRotation(RotateBy180);
360 by Adam Reichold
manual merge of future branch
1856
        break;
1857
    }
1858
}
1859
1860
void DocumentView::rotateRight()
1861
{
953 by Adam Reichold
results of a first glancing review preparing for the next beta release
1862
    switch(m_rotation)
360 by Adam Reichold
manual merge of future branch
1863
    {
813 by Adam Reichold
move page item enumerations into global header
1864
    default:
818 by Adam Reichold
move print options into separate header and rename rotation enum slightly
1865
    case RotateBy0:
813 by Adam Reichold
move page item enumerations into global header
1866
        setRotation(RotateBy90);
1867
        break;
1868
    case RotateBy90:
1869
        setRotation(RotateBy180);
1870
        break;
1871
    case RotateBy180:
1872
        setRotation(RotateBy270);
1873
        break;
1874
    case RotateBy270:
818 by Adam Reichold
move print options into separate header and rename rotation enum slightly
1875
        setRotation(RotateBy0);
360 by Adam Reichold
manual merge of future branch
1876
        break;
1877
    }
1878
}
1879
1063 by Adam Reichold
small cleanups in the document view
1880
void DocumentView::startPresentation()
360 by Adam Reichold
manual merge of future branch
1881
{
1147 by Adam Reichold
begin to make local variables immutable by default
1882
    const int screen = s_settings->presentationView().screen();
535 by Adam Reichold
turn the presentation view into a modal pop-up window to try to ease use on multi-monitor configurations
1883
1046.1.58 by Adam Reichold
simplify search task
1884
    PresentationView* presentationView = new PresentationView(m_pages);
535 by Adam Reichold
turn the presentation view into a modal pop-up window to try to ease use on multi-monitor configurations
1885
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
1886
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
1887
1888
    const QRect screenGeometry = screen != -1 ?
1889
                    QGuiApplication::screens().at(screen)->geometry() :
1890
                    QGuiApplication::primaryScreen()->geometry();
1891
1892
#else
1893
1894
    const QRect screenGeometry = QApplication::desktop()->screenGeometry(screen);
1895
1896
#endif // QT_VERSION
1897
1898
    presentationView->setGeometry(screenGeometry);
529 by Adam Reichold
add selecting the screen on which to show the presentation view by setting 'presentationView/screen'
1899
360 by Adam Reichold
manual merge of future branch
1900
    presentationView->show();
1901
    presentationView->setAttribute(Qt::WA_DeleteOnClose);
534 by Adam Reichold
make sure that the screen parameter for the presentation view is valid
1902
536 by Adam Reichold
instead of a modal pop-up window, synchronize current pages between document and presentation view
1903
    connect(this, SIGNAL(destroyed()), presentationView, SLOT(close()));
1411 by Adam Reichold
Clean-up the naming mess of synchronize presentation.
1904
    connect(this, SIGNAL(documentChanged()), presentationView, SLOT(close()));
536 by Adam Reichold
instead of a modal pop-up window, synchronize current pages between document and presentation view
1905
988 by Adam Reichold
also set initial rotation for presentation view
1906
    presentationView->setRotation(rotation());
1898.2.10 by Adam Reichold
Extend the presentation view to use render flags as well.
1907
    presentationView->setRenderFlags(renderFlags());
1908
537 by Adam Reichold
improve order of jumpToPage parameters to make document view and presentation view more compatible
1909
    presentationView->jumpToPage(currentPage(), false);
536 by Adam Reichold
instead of a modal pop-up window, synchronize current pages between document and presentation view
1910
1411 by Adam Reichold
Clean-up the naming mess of synchronize presentation.
1911
    if(s_settings->presentationView().synchronize())
538 by Adam Reichold
make presentation view synchronization internally configurable
1912
    {
1913
        connect(this, SIGNAL(currentPageChanged(int,bool)), presentationView, SLOT(jumpToPage(int,bool)));
1914
        connect(presentationView, SIGNAL(currentPageChanged(int,bool)), this, SLOT(jumpToPage(int,bool)));
1915
    }
360 by Adam Reichold
manual merge of future branch
1916
}
1917
1685.1.1 by Razi Alavizadeh
Fix computing current page.
1918
void DocumentView::on_verticalScrollBar_valueChanged()
360 by Adam Reichold
manual merge of future branch
1919
{
2041.2.9 by Adam Reichold
Instead of disconnecting and reconnecting slots to avoid redundant updates, block the signle relevant slot using a simple flag variable and an RAII helper.
1920
    if(m_verticalScrollBarChangedBlocked || !m_continuousMode)
1532 by Adam Reichold
Simplify method for tracking vertical view movement.
1921
    {
1922
        return;
1923
    }
1924
1686 by Adam Reichold
Merge page-numbers branch improving calculation of current page in continuous layouts.
1925
    int currentPage = -1;
1532 by Adam Reichold
Simplify method for tracking vertical view movement.
1926
    const QRectF visibleRect = mapToScene(viewport()->rect()).boundingRect();
1927
1950 by Adam Reichold
Small optimization to current page detection by starting it at the current instead of the first page.
1928
    for(int index = 0, count = m_pageItems.count(); index < count; ++index)
1532 by Adam Reichold
Simplify method for tracking vertical view movement.
1929
    {
1950 by Adam Reichold
Small optimization to current page detection by starting it at the current instead of the first page.
1930
        PageItem* page = m_pageItems.at((m_currentPage - 1 + index) % count);
1931
1686 by Adam Reichold
Merge page-numbers branch improving calculation of current page in continuous layouts.
1932
        const int pageNumber = page->index() + 1;
1933
        const QRectF pageRect = page->boundingRect().translated(page->pos());
1934
1935
        if(!pageRect.intersects(visibleRect))
463 by Adam Reichold
after last bugfix, explicit viewport culling is unnecessary non-continuous mode anyway
1936
        {
1532 by Adam Reichold
Simplify method for tracking vertical view movement.
1937
            page->cancelRender();
463 by Adam Reichold
after last bugfix, explicit viewport culling is unnecessary non-continuous mode anyway
1938
        }
1686 by Adam Reichold
Merge page-numbers branch improving calculation of current page in continuous layouts.
1939
        else if(currentPage == -1 &&
1940
                 m_layout->currentPage(pageNumber) == pageNumber &&
1941
                 m_layout->isCurrentPage(visibleRect, pageRect))
1685.1.1 by Razi Alavizadeh
Fix computing current page.
1942
        {
1686 by Adam Reichold
Merge page-numbers branch improving calculation of current page in continuous layouts.
1943
            currentPage = pageNumber;
1685.1.1 by Razi Alavizadeh
Fix computing current page.
1944
        }
1532 by Adam Reichold
Simplify method for tracking vertical view movement.
1945
    }
1946
1685.1.1 by Razi Alavizadeh
Fix computing current page.
1947
    if(currentPage != -1 && m_currentPage != currentPage)
1532 by Adam Reichold
Simplify method for tracking vertical view movement.
1948
    {
1685.1.1 by Razi Alavizadeh
Fix computing current page.
1949
        m_currentPage = currentPage;
1950
1951
        emit currentPageChanged(m_currentPage);
1952
1953
        if(s_settings->documentView().highlightCurrentThumbnail())
360 by Adam Reichold
manual merge of future branch
1954
        {
1685.1.1 by Razi Alavizadeh
Fix computing current page.
1955
            for(int index = 0; index < m_thumbnailItems.count(); ++index)
360 by Adam Reichold
manual merge of future branch
1956
            {
1687 by Adam Reichold
Improve naming of thumbnail highlighting Boolean property.
1957
                m_thumbnailItems.at(index)->setHighlighted(index == m_currentPage - 1);
360 by Adam Reichold
manual merge of future branch
1958
            }
1959
        }
1960
    }
1961
}
1962
1531 by Adam Reichold
Check for deletion before issueing auto-refresh.
1963
void DocumentView::on_autoRefresh_timeout()
1964
{
1965
    if(m_fileInfo.exists())
1966
    {
1967
        refresh();
1968
    }
1535 by Adam Reichold
Mark document as modified when it can't be found by auto-refresh to give the user a change to save it.
1969
    else
1970
    {
1971
        m_wasModified = true;
1972
1973
        emit documentModified();
1974
    }
1531 by Adam Reichold
Check for deletion before issueing auto-refresh.
1975
}
1976
366 by Adam Reichold
add prefetch and make culling thread-safe
1977
void DocumentView::on_prefetch_timeout()
1978
{
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
1979
    const QPair< int, int > prefetchRange = m_layout->prefetchRange(m_currentPage, m_pages.count());
1582 by Adam Reichold
Make prefetching aware of tiling in the sense that we allow to prefetch as many tiles as we would prefetch pages without tiling enabled.
1980
1981
    const int maxCost = prefetchRange.second - prefetchRange.first + 1;
1982
    int cost = 0;
1983
1984
    for(int index = m_currentPage - 1; index <= prefetchRange.second - 1; ++index)
1985
    {
1986
        cost += m_pageItems.at(index)->startRender(true);
1987
1988
        if(cost >= maxCost)
1989
        {
1990
            return;
1991
        }
1992
    }
1993
1994
    for(int index = m_currentPage - 1; index >= prefetchRange.first - 1; --index)
1995
    {
1996
        cost += m_pageItems.at(index)->startRender(true);
1997
1998
        if(cost >= maxCost)
1999
        {
2000
            return;
1574 by Adam Reichold
Do not try to prefetch completely visible pages and do not show page decorations in presentation mode.
2001
        }
366 by Adam Reichold
add prefetch and make culling thread-safe
2002
    }
2003
}
2004
1162 by Adam Reichold
use document view highlight instead of page item highlights for SyncTeX forward search, so that highlight all coninues to work if a search was conducted
2005
void DocumentView::on_temporaryHighlight_timeout()
2006
{
2007
    m_highlight->setVisible(false);
2008
}
2009
1782 by Adam Reichold
Paint search progress in the document items of the extended search dock view.
2010
void DocumentView::on_searchTask_progressChanged(int progress)
2011
{
2012
    s_searchModel->updateProgress(this);
2013
2014
    emit searchProgressChanged(progress);
2015
}
2016
1717.1.1 by Razi Alavizadeh
Remove parts of code related to storing search results, and just use received results for highlighting.
2017
void DocumentView::on_searchTask_resultsReady(int index, const QList< QRectF >& results)
1163 by Adam Reichold
minor shuffling around for clearer organization
2018
{
2019
    if(m_searchTask->wasCanceled())
2020
    {
2021
        return;
2022
    }
2023
1719 by Adam Reichold
Merge central search model.
2024
    s_searchModel->insertResults(this, index + 1, results);
1163 by Adam Reichold
minor shuffling around for clearer organization
2025
2026
    if(m_highlightAll)
2027
    {
1717.1.1 by Razi Alavizadeh
Remove parts of code related to storing search results, and just use received results for highlighting.
2028
        m_pageItems.at(index)->setHighlights(results);
2029
        m_thumbnailItems.at(index)->setHighlights(results);
1163 by Adam Reichold
minor shuffling around for clearer organization
2030
    }
2031
2032
    if(s_settings->documentView().limitThumbnailsToResults())
2033
    {
2034
        prepareThumbnailsScene();
2035
    }
2036
1719 by Adam Reichold
Merge central search model.
2037
    if(!results.isEmpty() && !m_currentResult.isValid())
1717.1.5 by Razi Alavizadeh
Track the current result of views and implement "find". (now using central search model)
2038
    {
2039
        setFocus();
2040
1719 by Adam Reichold
Merge central search model.
2041
        findNext();
1717.1.5 by Razi Alavizadeh
Track the current result of views and implement "find". (now using central search model)
2042
    }
1163 by Adam Reichold
minor shuffling around for clearer organization
2043
}
2044
1637.1.9 by Adam Reichold
Push the crop rect back into the tile items to properly handle the tiled case.
2045
void DocumentView::on_pages_cropRectChanged()
1637.1.4 by Adam Reichold
Relayout on crop box change.
2046
{
2047
    qreal left = 0.0, top = 0.0;
2048
    saveLeftAndTop(left, top);
2049
2050
    prepareScene();
2051
    prepareView(left, top);
2052
}
2053
1637.1.9 by Adam Reichold
Push the crop rect back into the tile items to properly handle the tiled case.
2054
void DocumentView::on_thumbnails_cropRectChanged()
1637.1.4 by Adam Reichold
Relayout on crop box change.
2055
{
2056
    prepareThumbnailsScene();
2057
}
2058
1494 by Adam Reichold
Add event handling to open internal links in new tab by middle clicking.
2059
void DocumentView::on_pages_linkClicked(bool newTab, int page, qreal left, qreal top)
360 by Adam Reichold
manual merge of future branch
2060
{
1494 by Adam Reichold
Add event handling to open internal links in new tab by middle clicking.
2061
    if(newTab)
2062
    {
2063
        emit linkClicked(page);
2064
    }
2065
    else
2066
    {
1881.1.2 by Adam Reichold
Use quiet NaN as default value for page-relative positions instead of explicit flag for more flexibility to indicate optional position changes.
2067
        jumpToPage(page, true, left, top);
1494 by Adam Reichold
Add event handling to open internal links in new tab by middle clicking.
2068
    }
360 by Adam Reichold
manual merge of future branch
2069
}
2070
1732 by Adam Reichold
Also make it possible to force opening a new tab (instead activating an existing one) for external document links.
2071
void DocumentView::on_pages_linkClicked(bool newTab, const QString& fileName, int page)
2072
{
1981 by Adam Reichold
Add support for outline links to external files.
2073
    emit linkClicked(newTab, resolveFileName(fileName), page);
1732 by Adam Reichold
Also make it possible to force opening a new tab (instead activating an existing one) for external document links.
2074
}
2075
360 by Adam Reichold
manual merge of future branch
2076
void DocumentView::on_pages_linkClicked(const QString& url)
2077
{
1046.1.41 by Adam Reichold
begin transition to the new settings class
2078
    if(s_settings->documentView().openUrl())
360 by Adam Reichold
manual merge of future branch
2079
    {
1981 by Adam Reichold
Add support for outline links to external files.
2080
        QDesktopServices::openUrl(resolveUrl(url));
360 by Adam Reichold
manual merge of future branch
2081
    }
2082
    else
2083
    {
2084
        QMessageBox::information(this, tr("Information"), tr("Opening URL is disabled in the settings."));
2085
    }
2086
}
2087
567 by Adam Reichold
improve rubber band signalling inside the page item
2088
void DocumentView::on_pages_rubberBandFinished()
515 by Adam Reichold
enable waiting for rubber band indicated by main window interaction
2089
{
813 by Adam Reichold
move page item enumerations into global header
2090
    setRubberBandMode(ModifiersMode);
515 by Adam Reichold
enable waiting for rubber band indicated by main window interaction
2091
}
2092
1952 by Adam Reichold
Remove the old SyncTeX code paths which were used for double-clicking.
2093
void DocumentView::on_pages_zoomToSelection(int page, const QRectF& rect)
1497 by Adam Reichold
Implement a zoom-to-selection action using the middle mouse button.
2094
{
1629 by Adam Reichold
Do not try to zomm to empty selection to prevent divide by zero.
2095
    if(rect.isEmpty())
2096
    {
2097
        return;
2098
    }
2099
1497 by Adam Reichold
Implement a zoom-to-selection action using the middle mouse button.
2100
    const qreal visibleWidth = m_layout->visibleWidth(viewport()->width());
2101
    const qreal visibleHeight = m_layout->visibleHeight(viewport()->height());
2102
1898.2.17 by Adam Reichold
Do not reuse the crop rectangle to compute the displayed width if it will be invalidated by changing the trim-margins flag.
2103
    const QSizeF displayedSize = m_pageItems.at(page - 1)->displayedSize();
1497 by Adam Reichold
Implement a zoom-to-selection action using the middle mouse button.
2104
1898.2.17 by Adam Reichold
Do not reuse the crop rectangle to compute the displayed width if it will be invalidated by changing the trim-margins flag.
2105
    setScaleFactor(qMin(qMin(visibleWidth / displayedSize.width() / rect.width(),
2106
                             visibleHeight / displayedSize.height() / rect.height()),
1497 by Adam Reichold
Implement a zoom-to-selection action using the middle mouse button.
2107
                        Defaults::DocumentView::maximumScaleFactor()));
2108
1558 by Adam Reichold
Explicitly request scale-factor mode when zooming to selection.
2109
    setScaleMode(ScaleFactorMode);
2110
1881.1.2 by Adam Reichold
Use quiet NaN as default value for page-relative positions instead of explicit flag for more flexibility to indicate optional position changes.
2111
    jumpToPage(page, false, rect.left(), rect.top());
1497 by Adam Reichold
Implement a zoom-to-selection action using the middle mouse button.
2112
}
2113
2041.2.12 by Adam Reichold
Fix usage of QList in the bookmark and search models and various small performance issues reported by the clazy tool using the checks of "level0,level1,level2,no-missing-qobject-macro,no-qstring-allocations,no-copyable-polymorphic,no-ctor-missing-parent-argument,no-reserve-candidates".
2114
void DocumentView::on_pages_openInSourceEditor(int page, QPointF pos)
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
2115
{
2116
#ifdef WITH_SYNCTEX
2117
2118
    if(const DocumentView::SourceLink sourceLink = scanForSourceLink(m_fileInfo.absoluteFilePath(), page, pos))
2119
    {
2120
        openInSourceEditor(sourceLink);
2121
    }
2122
    else
2123
    {
2124
        QMessageBox::warning(this, tr("Warning"), tr("SyncTeX data for '%1' could not be found.").arg(m_fileInfo.absoluteFilePath()));
2125
    }
2126
2127
#else
2128
2129
    Q_UNUSED(page);
2130
    Q_UNUSED(pos);
2131
2132
#endif // WITH_SYNCTEX
2133
}
2134
1245.1.1 by Adam Reichold
first implementation of ask-to-save function, being pessimistic about the possibility of modifications and without visual indication yet
2135
void DocumentView::on_pages_wasModified()
2136
{
2137
    m_wasModified = true;
1414 by Adam Reichold
Remove all direct usage of DocumentView::filePath.
2138
2139
    emit documentModified();
1245.1.1 by Adam Reichold
first implementation of ask-to-save function, being pessimistic about the possibility of modifications and without visual indication yet
2140
}
2141
360 by Adam Reichold
manual merge of future branch
2142
void DocumentView::resizeEvent(QResizeEvent* event)
2143
{
1806 by Adam Reichold
Disconnect vertial scroll bar value-change signal during resize events and synchronize setting and storing scroll bar position.
2144
    qreal left = 0.0, top = 0.0;
2145
    saveLeftAndTop(left, top);
2146
360 by Adam Reichold
manual merge of future branch
2147
    QGraphicsView::resizeEvent(event);
2148
814 by Adam Reichold
move document view enumerations and print options to global header
2149
    if(m_scaleMode != ScaleFactorMode)
360 by Adam Reichold
manual merge of future branch
2150
    {
2151
        prepareScene();
372 by Adam Reichold
save left and top for return
2152
        prepareView(left, top);
360 by Adam Reichold
manual merge of future branch
2153
    }
2154
}
2155
2156
void DocumentView::keyPressEvent(QKeyEvent* event)
2157
{
1803 by Adam Reichold
Also handle the general case when text field keyboard movement keys have been redefined.
2158
    foreach(const PageItem* page, m_pageItems)
2159
    {
2160
        if(page->showsAnnotationOverlay() || page->showsFormFieldOverlay())
2161
        {
2162
            QGraphicsView::keyPressEvent(event);
2163
            return;
2164
        }
2165
    }
2166
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2167
    const QKeySequence keySequence(event->modifiers() | event->key());
1347 by Adam Reichold
reorganize key event handler to separate masking keys from handling additional behavior
2168
2169
    int maskedKey = -1;
1980 by Adam Reichold
Do some copy editing of the mouse and key event handling for better readability.
2170
    bool maskedKeyActive = false;
2171
2172
    switch(event->key())
2173
    {
2174
    case Qt::Key_PageUp:
2175
    case Qt::Key_PageDown:
2176
    case Qt::Key_Up:
2177
    case Qt::Key_Down:
2178
    case Qt::Key_Left:
2179
    case Qt::Key_Right:
2180
        maskedKeyActive = true;
2181
        break;
2182
    }
1017 by Adam Reichold
make return to page, skip forward/backward main view actions
2183
1108 by Adam Reichold
implement support for multiple movement shortcuts in the document view
2184
    if(s_shortcutHandler->matchesSkipBackward(keySequence))
1017 by Adam Reichold
make return to page, skip forward/backward main view actions
2185
    {
1347 by Adam Reichold
reorganize key event handler to separate masking keys from handling additional behavior
2186
        maskedKey = Qt::Key_PageUp;
1017 by Adam Reichold
make return to page, skip forward/backward main view actions
2187
    }
1108 by Adam Reichold
implement support for multiple movement shortcuts in the document view
2188
    else if(s_shortcutHandler->matchesSkipForward(keySequence))
1017 by Adam Reichold
make return to page, skip forward/backward main view actions
2189
    {
1347 by Adam Reichold
reorganize key event handler to separate masking keys from handling additional behavior
2190
        maskedKey = Qt::Key_PageDown;
1017 by Adam Reichold
make return to page, skip forward/backward main view actions
2191
    }
1108 by Adam Reichold
implement support for multiple movement shortcuts in the document view
2192
    else if(s_shortcutHandler->matchesMoveUp(keySequence))
1025 by Adam Reichold
make movement shortcuts configurable as well and hence remove hard-coded Vim-style movement shortcuts
2193
    {
1347 by Adam Reichold
reorganize key event handler to separate masking keys from handling additional behavior
2194
        maskedKey = Qt::Key_Up;
1025 by Adam Reichold
make movement shortcuts configurable as well and hence remove hard-coded Vim-style movement shortcuts
2195
    }
1108 by Adam Reichold
implement support for multiple movement shortcuts in the document view
2196
    else if(s_shortcutHandler->matchesMoveDown(keySequence))
1025 by Adam Reichold
make movement shortcuts configurable as well and hence remove hard-coded Vim-style movement shortcuts
2197
    {
1347 by Adam Reichold
reorganize key event handler to separate masking keys from handling additional behavior
2198
        maskedKey = Qt::Key_Down;
1025 by Adam Reichold
make movement shortcuts configurable as well and hence remove hard-coded Vim-style movement shortcuts
2199
    }
1108 by Adam Reichold
implement support for multiple movement shortcuts in the document view
2200
    else if(s_shortcutHandler->matchesMoveLeft(keySequence))
1025 by Adam Reichold
make movement shortcuts configurable as well and hence remove hard-coded Vim-style movement shortcuts
2201
    {
1347 by Adam Reichold
reorganize key event handler to separate masking keys from handling additional behavior
2202
        maskedKey = Qt::Key_Left;
1025 by Adam Reichold
make movement shortcuts configurable as well and hence remove hard-coded Vim-style movement shortcuts
2203
    }
1108 by Adam Reichold
implement support for multiple movement shortcuts in the document view
2204
    else if(s_shortcutHandler->matchesMoveRight(keySequence))
1025 by Adam Reichold
make movement shortcuts configurable as well and hence remove hard-coded Vim-style movement shortcuts
2205
    {
1347 by Adam Reichold
reorganize key event handler to separate masking keys from handling additional behavior
2206
        maskedKey = Qt::Key_Right;
1017 by Adam Reichold
make return to page, skip forward/backward main view actions
2207
    }
1980 by Adam Reichold
Do some copy editing of the mouse and key event handling for better readability.
2208
    else if(maskedKeyActive)
1117 by Adam Reichold
do more effective shadowing of default scroll area keyboard shortcuts
2209
    {
1141 by Adam Reichold
simplify keyboard handling in the document view
2210
        event->ignore();
2211
        return;
1117 by Adam Reichold
do more effective shadowing of default scroll area keyboard shortcuts
2212
    }
1017 by Adam Reichold
make return to page, skip forward/backward main view actions
2213
1429 by Adam Reichold
Fix handling of masked keys in document view so that special jumps are not affected by the graphics view's normal functionality.
2214
    if(maskedKey == -1)
1358.1.20 by Adam Reichold
don't jump pages via movement keys if overlays are active
2215
    {
2216
        QGraphicsView::keyPressEvent(event);
2217
    }
1429 by Adam Reichold
Fix handling of masked keys in document view so that special jumps are not affected by the graphics view's normal functionality.
2218
    else
1358.1.22 by Adam Reichold
only check for active overlay on key press event if any of the problematic movement keys is actually active
2219
    {
2220
        if(!m_continuousMode)
2221
        {
2106 by Adam Reichold
Merge page skipping code paths for move up/down and skip up/down key presses.
2222
            if((maskedKey == Qt::Key_Up || maskedKey == Qt::Key_PageUp) && verticalScrollBar()->value() == verticalScrollBar()->minimum() && m_currentPage != 1)
1358.1.22 by Adam Reichold
only check for active overlay on key press event if any of the problematic movement keys is actually active
2223
            {
2224
                previousPage();
2225
2226
                verticalScrollBar()->setValue(verticalScrollBar()->maximum());
2227
2228
                event->accept();
2229
                return;
2230
            }
2106 by Adam Reichold
Merge page skipping code paths for move up/down and skip up/down key presses.
2231
            else if((maskedKey == Qt::Key_Down || maskedKey == Qt::Key_PageDown) && verticalScrollBar()->value() == verticalScrollBar()->maximum() && m_currentPage != m_layout->currentPage(m_pages.count()))
1358.1.22 by Adam Reichold
only check for active overlay on key press event if any of the problematic movement keys is actually active
2232
            {
2233
                nextPage();
2234
2235
                verticalScrollBar()->setValue(verticalScrollBar()->minimum());
2236
2237
                event->accept();
2238
                return;
2239
            }
2240
        }
2241
2106 by Adam Reichold
Merge page skipping code paths for move up/down and skip up/down key presses.
2242
        if((maskedKey == Qt::Key_Up && verticalScrollBar()->minimum() == verticalScrollBar()->maximum()) ||
2243
           (maskedKey == Qt::Key_Left && !horizontalScrollBar()->isVisible()))
2244
        {
2245
            previousPage();
2246
2247
            event->accept();
2248
            return;
2249
        }
2250
        else if((maskedKey == Qt::Key_Down && verticalScrollBar()->minimum() == verticalScrollBar()->maximum()) ||
2251
                (maskedKey == Qt::Key_Right && !horizontalScrollBar()->isVisible()))
1347 by Adam Reichold
reorganize key event handler to separate masking keys from handling additional behavior
2252
        {
2253
            nextPage();
2254
2255
            event->accept();
2256
            return;
2257
        }
1429 by Adam Reichold
Fix handling of masked keys in document view so that special jumps are not affected by the graphics view's normal functionality.
2258
2259
        QKeyEvent keyEvent(event->type(), maskedKey, Qt::NoModifier, event->text(), event->isAutoRepeat(), event->count());
2260
        QGraphicsView::keyPressEvent(&keyEvent);
1347 by Adam Reichold
reorganize key event handler to separate masking keys from handling additional behavior
2261
    }
360 by Adam Reichold
manual merge of future branch
2262
}
2263
1769 by Adam Reichold
Use the Qt-defined forward/backward mouse buttons to trigger those actions within the document view.
2264
void DocumentView::mousePressEvent(QMouseEvent* event)
2265
{
1770 by Adam Reichold
Use the Qt4-compatible forward/backward mouse button definitions.
2266
    if(event->button() == Qt::XButton1)
1769 by Adam Reichold
Use the Qt-defined forward/backward mouse buttons to trigger those actions within the document view.
2267
    {
2268
        event->accept();
2269
2270
        jumpBackward();
2271
    }
1770 by Adam Reichold
Use the Qt4-compatible forward/backward mouse button definitions.
2272
    else if(event->button() == Qt::XButton2)
1769 by Adam Reichold
Use the Qt-defined forward/backward mouse buttons to trigger those actions within the document view.
2273
    {
2274
        event->accept();
2275
2276
        jumpForward();
2277
    }
2278
2279
    QGraphicsView::mousePressEvent(event);
2280
}
2281
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2282
void DocumentView::wheelEvent(QWheelEvent* event)
2283
{
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2284
    const bool forward = rotatedForward(event);
2285
1980 by Adam Reichold
Do some copy editing of the mouse and key event handling for better readability.
2286
    const bool noModifiersActive = event->modifiers() == Qt::NoModifier;
2287
    const bool zoomModifiersActive = modifiersAreActive(event, s_settings->documentView().zoomModifiers());
2288
    const bool rotateModifiersActive = modifiersAreActive(event, s_settings->documentView().rotateModifiers());
2289
    const bool scrollModifiersActive = modifiersAreActive(event, s_settings->documentView().scrollModifiers());
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
2290
2291
    if(zoomModifiersActive)
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2292
    {
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2293
        if(forward)
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2294
        {
2295
            zoomIn();
2296
        }
2297
        else
2298
        {
2299
            zoomOut();
2300
        }
2301
2302
        event->accept();
2303
        return;
2304
    }
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
2305
    else if(rotateModifiersActive)
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2306
    {
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2307
        if(forward)
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2308
        {
2309
            rotateLeft();
2310
        }
2311
        else
2312
        {
2313
            rotateRight();
2314
        }
2315
2316
        event->accept();
2317
        return;
2318
    }
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
2319
    else if(scrollModifiersActive)
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2320
    {
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2321
#if QT_VERSION >= QT_VERSION_CHECK(5,15,0)
2322
2323
        QPoint pixelDelta = event->pixelDelta();
2324
        QPoint angleDelta = event->angleDelta();
2325
2326
        if(s_settings->documentView().scrollModifiers() != Qt::AltModifier)
2327
        {
2328
            qSwap(pixelDelta.rx(), pixelDelta.ry());
2329
            qSwap(angleDelta.rx(), angleDelta.ry());
2330
        }
2331
2332
        QWheelEvent wheelEvent(event->position(), event->globalPosition(), pixelDelta, angleDelta, event->buttons(), Qt::AltModifier, event->phase(), event->inverted(), event->source());
2333
2334
#else
2335
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2336
        QWheelEvent wheelEvent(event->pos(), event->delta(), event->buttons(), Qt::AltModifier, Qt::Horizontal);
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2337
2338
#endif // QT_VERSION
2339
1063 by Adam Reichold
small cleanups in the document view
2340
        QGraphicsView::wheelEvent(&wheelEvent);
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2341
2342
        event->accept();
2343
        return;
2344
    }
1980 by Adam Reichold
Do some copy editing of the mouse and key event handling for better readability.
2345
    else if(noModifiersActive && !m_continuousMode)
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2346
    {
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2347
        if(forward && verticalScrollBar()->value() == verticalScrollBar()->minimum() && m_currentPage != 1)
1930 by Adam Reichold
Do some minor code clean ups.
2348
        {
2349
            previousPage();
2350
2351
            verticalScrollBar()->setValue(verticalScrollBar()->maximum());
2352
2353
            event->accept();
2354
            return;
2355
        }
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2356
        else if(!forward && verticalScrollBar()->value() == verticalScrollBar()->maximum() && m_currentPage != m_layout->currentPage(m_pages.count()))
1930 by Adam Reichold
Do some minor code clean ups.
2357
        {
2358
            nextPage();
2359
2360
            verticalScrollBar()->setValue(verticalScrollBar()->minimum());
2361
2362
            event->accept();
2363
            return;
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2364
        }
2365
    }
2366
2367
    QGraphicsView::wheelEvent(event);
2368
}
2369
2370
void DocumentView::contextMenuEvent(QContextMenuEvent* event)
2371
{
1690 by Adam Reichold
Enable the use of the right mouse button as a modifier.
2372
    if(event->reason() == QContextMenuEvent::Mouse && modifiersUseMouseButton(s_settings, Qt::RightButton))
2373
    {
2374
        event->accept();
2375
        return;
2376
    }
2377
573 by Adam Reichold
handle removing annotations using context menu events and generally use context menu event handlers hence respecting the context menu policy
2378
    event->setAccepted(false);
2379
2380
    QGraphicsView::contextMenuEvent(event);
2381
2382
    if(!event->isAccepted())
2383
    {
2384
        event->setAccepted(true);
2385
1013 by Adam Reichold
handle main view context menu in the main window reduncing action
2386
        emit customContextMenuRequested(event->pos());
465 by Adam Reichold
handle context menu in mousePressEvent to ensure compatibility with PageItem mouse interaction
2387
    }
2388
}
2389
929 by Adam Reichold
fix build without CUPS
2390
#ifdef WITH_CUPS
2391
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
2392
bool DocumentView::printUsingCUPS(QPrinter* printer, const PrintOptions& printOptions, int fromPage, int toPage)
892 by Adam Reichold
Separate out the two different printing implementations.
2393
{
2394
    cups_dest_t* dests = 0;
2108 by Adam Reichold
Fix up page-set sent to CUPS as Qt's print dialog will adjust it for page ranges beginning at even pages.
2395
    const int num_dests = cupsGetDests(&dests);
2396
2397
    cups_dest_t* const dest = cupsGetDest(printer->printerName().toUtf8(), 0, num_dests, dests);
2398
2399
    if(dest == 0)
2400
    {
2401
        qWarning() << cupsLastErrorString();
2402
2403
        cupsFreeDests(num_dests, dests);
2404
2405
        return false;
2406
    }
2407
2408
    cups_option_t* options = 0;
892 by Adam Reichold
Separate out the two different printing implementations.
2409
    int num_options = 0;
1926 by Adam Reichold
Small clean up of error handling in print methods.
2410
2411
    for(int index = 0; index < dest->num_options; ++index)
2412
    {
2413
        num_options = cupsAddOption(dest->options[index].name, dest->options[index].value, num_options, &options);
2414
    }
2415
2416
    const QStringList cupsOptions = printer->printEngine()->property(QPrintEngine::PrintEnginePropertyKey(0xfe00)).toStringList();
2417
2418
    for(int index = 0; index < cupsOptions.count() - 1; index += 2)
2419
    {
2083 by Adam Reichold
Use UTF-8 instead of the unspecified local 8-bit encoding since the IPP specification actually mandates it.
2420
        num_options = cupsAddOption(cupsOptions.at(index).toUtf8(), cupsOptions.at(index + 1).toUtf8(), num_options, &options);
1926 by Adam Reichold
Small clean up of error handling in print methods.
2421
    }
1389 by Adam Reichold
try to copy the CUPS options stored in the private print engine property under key 0xfe00
2422
892 by Adam Reichold
Separate out the two different printing implementations.
2423
#if QT_VERSION >= QT_VERSION_CHECK(4,7,0)
2424
2083 by Adam Reichold
Use UTF-8 instead of the unspecified local 8-bit encoding since the IPP specification actually mandates it.
2425
    num_options = cupsAddOption("copies", QString::number(printer->copyCount()).toUtf8(), num_options, &options);
892 by Adam Reichold
Separate out the two different printing implementations.
2426
2427
#endif // QT_VERSION
2428
1926 by Adam Reichold
Small clean up of error handling in print methods.
2429
    num_options = cupsAddOption("Collate", printer->collateCopies() ? "true" : "false", num_options, &options);
2430
2431
    switch(printer->pageOrder())
2432
    {
2433
    case QPrinter::FirstPageFirst:
2434
        num_options = cupsAddOption("outputorder", "normal", num_options, &options);
2435
        break;
2436
    case QPrinter::LastPageFirst:
2437
        num_options = cupsAddOption("outputorder", "reverse", num_options, &options);
2438
        break;
2439
    }
2440
2441
    num_options = cupsAddOption("fit-to-page", printOptions.fitToPage ? "true" : "false", num_options, &options);
2442
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2443
#if QT_VERSION >= QT_VERSION_CHECK(5,3,0)
2444
2445
    switch(printer->pageLayout().orientation())
2446
2447
#else
2448
1926 by Adam Reichold
Small clean up of error handling in print methods.
2449
    switch(printer->orientation())
2117 by Adam Reichold
First stab at making the application compatible with Qt versions 4, 5 and 6.
2450
2451
#endif // QT_VERSION
1926 by Adam Reichold
Small clean up of error handling in print methods.
2452
    {
2119 by Adam Reichold
Fix enum compatibility handling to support older GCC versions.
2453
    case PageOrientationValues::Portrait:
1926 by Adam Reichold
Small clean up of error handling in print methods.
2454
        num_options = cupsAddOption("landscape", "false", num_options, &options);
2455
        break;
2119 by Adam Reichold
Fix enum compatibility handling to support older GCC versions.
2456
    case PageOrientationValues::Landscape:
1926 by Adam Reichold
Small clean up of error handling in print methods.
2457
        num_options = cupsAddOption("landscape", "true", num_options, &options);
2458
        break;
2459
    }
2460
2461
    switch(printer->colorMode())
2462
    {
2463
    case QPrinter::Color:
2464
        num_options = addCMYKorRGBColorModel(dest, num_options, &options);
2006 by Adam Reichold
Also use the Ink in addition to the ColorModel option that seems to be used by Epson drivers.
2465
        num_options = cupsAddOption("Ink", "COLOR", num_options, &options);
1926 by Adam Reichold
Small clean up of error handling in print methods.
2466
        break;
2467
    case QPrinter::GrayScale:
2468
        num_options = cupsAddOption("ColorModel", "Gray", num_options, &options);
2006 by Adam Reichold
Also use the Ink in addition to the ColorModel option that seems to be used by Epson drivers.
2469
        num_options = cupsAddOption("Ink", "MONO", num_options, &options);
1926 by Adam Reichold
Small clean up of error handling in print methods.
2470
        break;
2471
    }
2472
2473
    switch(printer->duplex())
2474
    {
2475
    case QPrinter::DuplexNone:
2476
        num_options = cupsAddOption("sides", "one-sided", num_options, &options);
2477
        break;
2478
    case QPrinter::DuplexAuto:
2479
        break;
2480
    case QPrinter::DuplexLongSide:
2481
        num_options = cupsAddOption("sides", "two-sided-long-edge", num_options, &options);
2482
        break;
2483
    case QPrinter::DuplexShortSide:
2484
        num_options = cupsAddOption("sides", "two-sided-short-edge", num_options, &options);
2485
        break;
2486
    }
2487
2488
    int numberUp = 1;
892 by Adam Reichold
Separate out the two different printing implementations.
2489
1541 by Adam Reichold
Remove extended prints option page set and number-up as they are redundant with Qt's internal options since version 5.2.
2490
#if QT_VERSION < QT_VERSION_CHECK(5,2,0)
2491
1926 by Adam Reichold
Small clean up of error handling in print methods.
2492
    switch(printOptions.numberUp)
2493
    {
2494
    case PrintOptions::SinglePage:
2495
        num_options = cupsAddOption("number-up", "1", num_options, &options);
2496
        numberUp = 1;
2497
        break;
2498
    case PrintOptions::TwoPages:
2499
        num_options = cupsAddOption("number-up", "2", num_options, &options);
2500
        numberUp = 2;
2501
        break;
2502
    case PrintOptions::FourPages:
2503
        num_options = cupsAddOption("number-up", "4", num_options, &options);
2504
        numberUp = 4;
2505
        break;
2506
    case PrintOptions::SixPages:
2507
        num_options = cupsAddOption("number-up", "6", num_options, &options);
2508
        numberUp = 6;
2509
        break;
2510
    case PrintOptions::NinePages:
2511
        num_options = cupsAddOption("number-up", "9", num_options, &options);
2512
        numberUp = 9;
2513
        break;
2514
    case PrintOptions::SixteenPages:
2515
        num_options = cupsAddOption("number-up", "16", num_options, &options);
2516
        numberUp = 16;
2517
        break;
2518
    }
2519
2520
    switch(printOptions.numberUpLayout)
2521
    {
2522
    case PrintOptions::BottomTopLeftRight:
2523
        num_options = cupsAddOption("number-up-layout", "btlr", num_options, &options);
2524
        break;
2525
    case PrintOptions::BottomTopRightLeft:
2526
        num_options = cupsAddOption("number-up-layout", "btrl", num_options, &options);
2527
        break;
2528
    case PrintOptions::LeftRightBottomTop:
2529
        num_options = cupsAddOption("number-up-layout", "lrbt", num_options, &options);
2530
        break;
2531
    case PrintOptions::LeftRightTopBottom:
2532
        num_options = cupsAddOption("number-up-layout", "lrtb", num_options, &options);
2533
        break;
2534
    case PrintOptions::RightLeftBottomTop:
2535
        num_options = cupsAddOption("number-up-layout", "rlbt", num_options, &options);
2536
        break;
2537
    case PrintOptions::RightLeftTopBottom:
2538
        num_options = cupsAddOption("number-up-layout", "rltb", num_options, &options);
2539
        break;
2540
    case PrintOptions::TopBottomLeftRight:
2541
        num_options = cupsAddOption("number-up-layout", "tblr", num_options, &options);
2542
        break;
2543
    case PrintOptions::TopBottomRightLeft:
2544
        num_options = cupsAddOption("number-up-layout", "tbrl", num_options, &options);
2545
        break;
2546
    }
2547
2548
    switch(printOptions.pageSet)
2549
    {
2550
    case PrintOptions::AllPages:
2551
        break;
2552
    case PrintOptions::EvenPages:
2553
        num_options = cupsAddOption("page-set", "even", num_options, &options);
2554
        break;
2555
    case PrintOptions::OddPages:
2556
        num_options = cupsAddOption("page-set", "odd", num_options, &options);
2557
        break;
2558
    }
892 by Adam Reichold
Separate out the two different printing implementations.
2559
1932 by Adam Reichold
Prepare the PDF settings for Poppler version 0.35 which will allow to ignore the paper color.
2560
#else
1541 by Adam Reichold
Remove extended prints option page set and number-up as they are redundant with Qt's internal options since version 5.2.
2561
1926 by Adam Reichold
Small clean up of error handling in print methods.
2562
    {
2563
        bool ok = false;
2108 by Adam Reichold
Fix up page-set sent to CUPS as Qt's print dialog will adjust it for page ranges beginning at even pages.
2564
        const int value = QString::fromUtf8(cupsGetOption("number-up", num_options, options)).toInt(&ok);
2565
2566
        if(ok)
2567
        {
2568
            numberUp = value;
2569
        }
2570
    }
2571
2572
    if(fromPage % 2 == 0)
2573
    {
2574
        const QString value = QString::fromUtf8(cupsGetOption("page-set", num_options, options));
2575
2576
        if(value == "odd")
2577
        {
2578
            num_options = cupsAddOption("page-set", "even", num_options, &options);
2579
        }
2580
        else if(value == "even")
2581
        {
2582
            num_options = cupsAddOption("page-set", "odd", num_options, &options);
2583
        }
1926 by Adam Reichold
Small clean up of error handling in print methods.
2584
    }
1541 by Adam Reichold
Remove extended prints option page set and number-up as they are redundant with Qt's internal options since version 5.2.
2585
2586
#endif // QT_VERSION
2587
1926 by Adam Reichold
Small clean up of error handling in print methods.
2588
    fromPage = (fromPage - 1) / numberUp + 1;
2589
    toPage = (toPage - 1) / numberUp + 1;
2590
2086 by Adam Reichold
Do not overwrite page-ranges CUPS option when it was already set by Qt's print dialog.
2591
    if(cupsGetOption("page-ranges", num_options, options) == 0)
2592
    {
2593
        if(printOptions.pageRanges.isEmpty())
2594
        {
2595
            num_options = cupsAddOption("page-ranges", QString("%1-%2").arg(fromPage).arg(toPage).toUtf8(), num_options, &options);
2596
        }
2597
        else
2598
        {
2599
            num_options = cupsAddOption("page-ranges", printOptions.pageRanges.toUtf8(), num_options, &options);
2600
        }
1926 by Adam Reichold
Small clean up of error handling in print methods.
2601
    }
2602
2603
    QTemporaryFile temporaryFile;
2604
1927.1.5 by Adam Reichold
Add support to save images using Qt's built-in formats.
2605
    adjustFileTemplateSuffix(temporaryFile, m_fileInfo.suffix());
2606
1926 by Adam Reichold
Small clean up of error handling in print methods.
2607
    if(!temporaryFile.open())
2608
    {
2609
        cupsFreeDests(num_dests, dests);
2610
        cupsFreeOptions(num_options, options);
2611
2612
        return false;
2613
    }
2614
2615
    temporaryFile.close();
2616
2617
    if(!m_document->save(temporaryFile.fileName(), true))
2618
    {
2619
        cupsFreeDests(num_dests, dests);
2620
        cupsFreeOptions(num_options, options);
2621
2622
        return false;
2623
    }
2624
2108 by Adam Reichold
Fix up page-set sent to CUPS as Qt's print dialog will adjust it for page ranges beginning at even pages.
2625
    const int jobId = cupsPrintFile(dest->name, QFile::encodeName(temporaryFile.fileName()), m_fileInfo.completeBaseName().toUtf8(), num_options, options);
1926 by Adam Reichold
Small clean up of error handling in print methods.
2626
2627
    if(jobId < 1)
2628
    {
1033 by Adam Reichold
try to improve consistency of usage of qDebug() and friends
2629
        qWarning() << cupsLastErrorString();
892 by Adam Reichold
Separate out the two different printing implementations.
2630
    }
2631
2632
    cupsFreeDests(num_dests, dests);
2633
    cupsFreeOptions(num_options, options);
2634
2635
    return jobId >= 1;
2636
}
2637
929 by Adam Reichold
fix build without CUPS
2638
#endif // WITH_CUPS
2639
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
2640
bool DocumentView::printUsingQt(QPrinter* printer, const PrintOptions& printOptions, int fromPage, int toPage)
892 by Adam Reichold
Separate out the two different printing implementations.
2641
{
1063 by Adam Reichold
small cleanups in the document view
2642
    QScopedPointer< QProgressDialog > progressDialog(new QProgressDialog(this));
1413 by Adam Reichold
Store a QFileInfo instead of a plain path in the document view to reduce the number of temporary objects.
2643
    progressDialog->setLabelText(tr("Printing '%1'...").arg(m_fileInfo.completeBaseName()));
892 by Adam Reichold
Separate out the two different printing implementations.
2644
    progressDialog->setRange(fromPage - 1, toPage);
2645
1926 by Adam Reichold
Small clean up of error handling in print methods.
2646
    QPainter painter;
2647
2648
    if(!painter.begin(printer))
2649
    {
2650
        return false;
2651
    }
892 by Adam Reichold
Separate out the two different printing implementations.
2652
2653
    for(int index = fromPage - 1; index <= toPage - 1; ++index)
2654
    {
2655
        progressDialog->setValue(index);
2656
2657
        QApplication::processEvents();
2658
1308 by Adam Reichold
small improvements to the fallback printing code
2659
        painter.save();
2660
1521 by Adam Reichold
Follow Qt Creator style guide and use capital letter for namespaces and refactor Djvu link loading code.
2661
        const Model::Page* page = m_pages.at(index);
1063 by Adam Reichold
small cleanups in the document view
2662
2663
        if(printOptions.fitToPage)
2664
        {
1308 by Adam Reichold
small improvements to the fallback printing code
2665
            const qreal pageWidth = printer->physicalDpiX() / 72.0 * page->size().width();
2666
            const qreal pageHeight = printer->physicalDpiY() / 72.0 * page->size().width();
2667
2668
            const qreal scaleFactor = qMin(printer->width() / pageWidth, printer->height() / pageHeight);
2669
2670
            painter.setTransform(QTransform::fromScale(scaleFactor, scaleFactor));
1063 by Adam Reichold
small cleanups in the document view
2671
        }
2672
        else
2673
        {
1308 by Adam Reichold
small improvements to the fallback printing code
2674
            const qreal scaleFactorX = static_cast< qreal >(printer->logicalDpiX()) / static_cast< qreal >(printer->physicalDpiX());
2675
            const qreal scaleFactorY = static_cast< qreal >(printer->logicalDpiY()) / static_cast< qreal >(printer->physicalDpiY());
2676
2677
            painter.setTransform(QTransform::fromScale(scaleFactorX, scaleFactorY));
1063 by Adam Reichold
small cleanups in the document view
2678
        }
2679
1308 by Adam Reichold
small improvements to the fallback printing code
2680
        painter.drawImage(QPointF(), page->render(printer->physicalDpiX(), printer->physicalDpiY()));
1063 by Adam Reichold
small cleanups in the document view
2681
1308 by Adam Reichold
small improvements to the fallback printing code
2682
        painter.restore();
892 by Adam Reichold
Separate out the two different printing implementations.
2683
2684
        if(index < toPage - 1)
2685
        {
2686
            printer->newPage();
2687
        }
2688
2689
        QApplication::processEvents();
2690
2691
        if(progressDialog->wasCanceled())
2692
        {
1308 by Adam Reichold
small improvements to the fallback printing code
2693
            printer->abort();
2694
892 by Adam Reichold
Separate out the two different printing implementations.
2695
            return false;
2696
        }
2697
    }
2698
2699
    return true;
2700
}
2701
546 by Adam Reichold
large change implementing 'two pages with cover' layout mode
2702
void DocumentView::saveLeftAndTop(qreal& left, qreal& top) const
365 by Adam Reichold
save and restore viewport left and top on scale change
2703
{
1147 by Adam Reichold
begin to make local variables immutable by default
2704
    const PageItem* page = m_pageItems.at(m_currentPage - 1);
1881.1.9 by Adam Reichold
Use the uncropped bounding rect to compute page-relative positions.
2705
    const QRectF boundingRect = page->uncroppedBoundingRect().translated(page->pos());
1806 by Adam Reichold
Disconnect vertial scroll bar value-change signal during resize events and synchronize setting and storing scroll bar position.
2706
1812 by Adam Reichold
Simplified position computation breaks as invisible scroll bars have unsynchronized values w.r.t. scene coordinates.
2707
    const QPointF topLeft = mapToScene(viewport()->rect().topLeft());
1806 by Adam Reichold
Disconnect vertial scroll bar value-change signal during resize events and synchronize setting and storing scroll bar position.
2708
1812 by Adam Reichold
Simplified position computation breaks as invisible scroll bars have unsynchronized values w.r.t. scene coordinates.
2709
    left = (topLeft.x() - boundingRect.x()) / boundingRect.width();
2710
    top = (topLeft.y() - boundingRect.y()) / boundingRect.height();
365 by Adam Reichold
save and restore viewport left and top on scale change
2711
}
2712
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
2713
bool DocumentView::checkDocument(const QString& filePath, Model::Document* document, QVector< Model::Page* >& pages)
1470 by Adam Reichold
We did never support documents with zero pages, so check for that.
2714
{
2715
    if(document->isLocked())
2716
    {
2717
        QString password = QInputDialog::getText(this, tr("Unlock %1").arg(QFileInfo(filePath).completeBaseName()), tr("Password:"), QLineEdit::Password);
2718
2719
        if(document->unlock(password))
2720
        {
2721
            return false;
2722
        }
2723
    }
2724
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
2725
    const int numberOfPages = document->numberOfPages();
2726
2727
    if(numberOfPages == 0)
1470 by Adam Reichold
We did never support documents with zero pages, so check for that.
2728
    {
2729
        qWarning() << "No pages were found in document at" << filePath;
2730
2731
        return false;
2732
    }
2733
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
2734
    pages.reserve(numberOfPages);
2735
2736
    for(int index = 0; index < numberOfPages; ++index)
2737
    {
2738
        Model::Page* page = document->page(index);
2739
2740
        if(page == 0)
2741
        {
2742
            qWarning() << "No page" << index << "was found in document at" << filePath;
2743
2744
            return false;
2745
        }
2746
2747
        pages.append(page);
2748
    }
2749
1470 by Adam Reichold
We did never support documents with zero pages, so check for that.
2750
    return true;
2751
}
2752
1473 by Adam Reichold
Add interface to load document-supplied defaults which will overwrite per-tab settings but will be overwritten by per-file settings.
2753
void DocumentView::loadDocumentDefaults()
2754
{
2755
    if(m_document->wantsContinuousMode())
2756
    {
1490 by Adam Reichold
Do not call public setter from loadDocumentDefaults as this would emit unwanted signals and call prepareScene.
2757
        m_continuousMode = true;
1473 by Adam Reichold
Add interface to load document-supplied defaults which will overwrite per-tab settings but will be overwritten by per-file settings.
2758
    }
2759
2760
    if(m_document->wantsSinglePageMode())
2761
    {
1490 by Adam Reichold
Do not call public setter from loadDocumentDefaults as this would emit unwanted signals and call prepareScene.
2762
        m_layout.reset(new SinglePageLayout);
1473 by Adam Reichold
Add interface to load document-supplied defaults which will overwrite per-tab settings but will be overwritten by per-file settings.
2763
    }
2764
    else if(m_document->wantsTwoPagesMode())
2765
    {
1490 by Adam Reichold
Do not call public setter from loadDocumentDefaults as this would emit unwanted signals and call prepareScene.
2766
        m_layout.reset(new TwoPagesLayout);
1473 by Adam Reichold
Add interface to load document-supplied defaults which will overwrite per-tab settings but will be overwritten by per-file settings.
2767
    }
2768
    else if(m_document->wantsTwoPagesWithCoverPageMode())
2769
    {
1490 by Adam Reichold
Do not call public setter from loadDocumentDefaults as this would emit unwanted signals and call prepareScene.
2770
        m_layout.reset(new TwoPagesWithCoverPageLayout);
1473 by Adam Reichold
Add interface to load document-supplied defaults which will overwrite per-tab settings but will be overwritten by per-file settings.
2771
    }
2772
2773
    if(m_document->wantsRightToLeftMode())
2774
    {
1490 by Adam Reichold
Do not call public setter from loadDocumentDefaults as this would emit unwanted signals and call prepareScene.
2775
        m_rightToLeftMode = true;
1473 by Adam Reichold
Add interface to load document-supplied defaults which will overwrite per-tab settings but will be overwritten by per-file settings.
2776
    }
2777
}
2778
1608 by Adam Reichold
Instead of always showing the vertical scroll bar for simpler visble area calculations, adjust the scroll bar policy based on the scale mode.
2779
void DocumentView::adjustScrollBarPolicy()
2780
{
2781
    switch(m_scaleMode)
2782
    {
2783
    default:
2784
    case ScaleFactorMode:
2785
        setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
2786
        setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
2787
        break;
2788
    case FitToPageWidthMode:
2789
        setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2790
        setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
2791
        break;
2792
    case FitToPageSizeMode:
2793
        setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
2794
        setVerticalScrollBarPolicy(m_continuousMode ? Qt::ScrollBarAsNeeded : Qt::ScrollBarAlwaysOff);
2795
        break;
2796
    }
2797
}
2798
1739 by Adam Reichold
Be more transactional when loading document by checking beforehand whether all indicated pages can be actually loaded.
2799
void DocumentView::prepareDocument(Model::Document* document, const QVector< Model::Page* >& pages)
360 by Adam Reichold
manual merge of future branch
2800
{
366 by Adam Reichold
add prefetch and make culling thread-safe
2801
    m_prefetchTimer->blockSignals(true);
372 by Adam Reichold
save left and top for return
2802
    m_prefetchTimer->stop();
366 by Adam Reichold
add prefetch and make culling thread-safe
2803
1778 by Adam Reichold
Provide separate slots for search cancellation and clearing of search results.
2804
    cancelSearch();
1719 by Adam Reichold
Merge central search model.
2805
    clearResults();
543 by Adam Reichold
fix a bug where the program crashes on refresh if highlight all is enabled
2806
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
2807
    qDeleteAll(m_pageItems);
2808
    qDeleteAll(m_thumbnailItems);
2809
1915 by Adam Reichold
Fix deleting the document model before its pages which can crash with MuPDF version 1.7.
2810
    qDeleteAll(m_pages);
2811
    m_pages = pages;
2812
1503 by Adam Reichold
Slightly simplify preparing the document.
2813
    delete m_document;
360 by Adam Reichold
manual merge of future branch
2814
    m_document = document;
2815
1503 by Adam Reichold
Slightly simplify preparing the document.
2816
    if(!m_autoRefreshWatcher->files().isEmpty())
2817
    {
2818
        m_autoRefreshWatcher->removePaths(m_autoRefreshWatcher->files());
2819
    }
2820
1046.1.41 by Adam Reichold
begin transition to the new settings class
2821
    if(s_settings->documentView().autoRefresh())
360 by Adam Reichold
manual merge of future branch
2822
    {
1413 by Adam Reichold
Store a QFileInfo instead of a plain path in the document view to reduce the number of temporary objects.
2823
        m_autoRefreshWatcher->addPath(m_fileInfo.filePath());
360 by Adam Reichold
manual merge of future branch
2824
    }
2825
1046.1.41 by Adam Reichold
begin transition to the new settings class
2826
    m_document->setPaperColor(s_settings->pageItem().paperColor());
739.1.1 by Adam Reichold
make the paper color used for the document configurable
2827
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
2828
    preparePages();
2829
    prepareThumbnails();
976 by Adam Reichold
prepare internally for per-tab color inversion
2830
    prepareBackground();
869 by Adam Reichold
merged Alexander Volkov's PostScript plug-in and changed plug-in preference to local before system-wide
2831
2040 by Adam Reichold
Improve naming consistency in the model accessor methods.
2832
    const Model::Outline outline = m_document->outline();
1996 by Adam Reichold
Reuse parent pointer in outline and properties models.
2833
2834
    if(!outline.empty())
2835
    {
2836
        m_outlineModel.reset(new OutlineModel(outline, this));
2837
    }
2838
    else
2839
    {
2840
        m_outlineModel.reset(new FallbackOutlineModel(this));
2841
    }
2842
2040 by Adam Reichold
Improve naming consistency in the model accessor methods.
2843
    Model::Properties properties = m_document->properties();
2007 by Adam Reichold
Extend the document properties with various miscellaneous file properties.
2844
2845
    addFileProperties(properties, m_fileInfo);
2846
2847
    m_propertiesModel.reset(new PropertiesModel(properties, this));
1208 by Adam Reichold
add fallback outline for documents without an outline included
2848
1046.1.41 by Adam Reichold
begin transition to the new settings class
2849
    if(s_settings->documentView().prefetch())
366 by Adam Reichold
add prefetch and make culling thread-safe
2850
    {
2851
        m_prefetchTimer->blockSignals(false);
2852
        m_prefetchTimer->start();
2853
    }
360 by Adam Reichold
manual merge of future branch
2854
}
2855
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
2856
void DocumentView::preparePages()
360 by Adam Reichold
manual merge of future branch
2857
{
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
2858
    m_pageItems.clear();
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
2859
    m_pageItems.reserve(m_pages.count());
360 by Adam Reichold
manual merge of future branch
2860
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
2861
    for(int index = 0; index < m_pages.count(); ++index)
360 by Adam Reichold
manual merge of future branch
2862
    {
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
2863
        PageItem* page = new PageItem(m_pages.at(index), index);
360 by Adam Reichold
manual merge of future branch
2864
566 by Adam Reichold
handle rubber band mode as document view property and simplify highlight all handling
2865
        page->setRubberBandMode(m_rubberBandMode);
360 by Adam Reichold
manual merge of future branch
2866
1046.1.3 by Adam Reichold
simplify scene management
2867
        scene()->addItem(page);
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
2868
        m_pageItems.append(page);
360 by Adam Reichold
manual merge of future branch
2869
1637.1.9 by Adam Reichold
Push the crop rect back into the tile items to properly handle the tiled case.
2870
        connect(page, SIGNAL(cropRectChanged()), SLOT(on_pages_cropRectChanged()));
1637.1.4 by Adam Reichold
Relayout on crop box change.
2871
1494 by Adam Reichold
Add event handling to open internal links in new tab by middle clicking.
2872
        connect(page, SIGNAL(linkClicked(bool,int,qreal,qreal)), SLOT(on_pages_linkClicked(bool,int,qreal,qreal)));
1732 by Adam Reichold
Also make it possible to force opening a new tab (instead activating an existing one) for external document links.
2873
        connect(page, SIGNAL(linkClicked(bool,QString,int)), SLOT(on_pages_linkClicked(bool,QString,int)));
360 by Adam Reichold
manual merge of future branch
2874
        connect(page, SIGNAL(linkClicked(QString)), SLOT(on_pages_linkClicked(QString)));
515 by Adam Reichold
enable waiting for rubber band indicated by main window interaction
2875
567 by Adam Reichold
improve rubber band signalling inside the page item
2876
        connect(page, SIGNAL(rubberBandFinished()), SLOT(on_pages_rubberBandFinished()));
590 by Adam Reichold
enable reverse SyncTeX search
2877
2124 by Adam Reichold
Add context menu item to append selected text to bookmark comment.
2878
        connect(page, SIGNAL(appendTextToBookmarkComment(int,QString)), SIGNAL(appendTextToBookmarkComment(int,QString)));
1952 by Adam Reichold
Remove the old SyncTeX code paths which were used for double-clicking.
2879
        connect(page, SIGNAL(zoomToSelection(int,QRectF)), SLOT(on_pages_zoomToSelection(int,QRectF)));
1969 by Adam Reichold
Add triggering of SyncTeX reverse search using keyboard modifiers and make it possible to explicitly disable keyboard modifiers.
2880
        connect(page, SIGNAL(openInSourceEditor(int,QPointF)), SLOT(on_pages_openInSourceEditor(int,QPointF)));
1245.1.1 by Adam Reichold
first implementation of ask-to-save function, being pessimistic about the possibility of modifications and without visual indication yet
2881
2882
        connect(page, SIGNAL(wasModified()), SLOT(on_pages_wasModified()));
360 by Adam Reichold
manual merge of future branch
2883
    }
2884
}
2885
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
2886
void DocumentView::prepareThumbnails()
360 by Adam Reichold
manual merge of future branch
2887
{
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
2888
    m_thumbnailItems.clear();
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
2889
    m_thumbnailItems.reserve(m_pages.count());
360 by Adam Reichold
manual merge of future branch
2890
1046.1.59 by Adam Reichold
also remove unnecessary numberOfPages member from document view
2891
    for(int index = 0; index < m_pages.count(); ++index)
360 by Adam Reichold
manual merge of future branch
2892
    {
1657.1.4 by Razi Alavizadeh
Use page label in outline and thumbnail views.
2893
        ThumbnailItem* page = new ThumbnailItem(m_pages.at(index), pageLabelFromNumber(index + 1), index);
360 by Adam Reichold
manual merge of future branch
2894
2895
        m_thumbnailsScene->addItem(page);
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
2896
        m_thumbnailItems.append(page);
360 by Adam Reichold
manual merge of future branch
2897
1637.1.9 by Adam Reichold
Push the crop rect back into the tile items to properly handle the tiled case.
2898
        connect(page, SIGNAL(cropRectChanged()), SLOT(on_thumbnails_cropRectChanged()));
1637.1.4 by Adam Reichold
Relayout on crop box change.
2899
1494 by Adam Reichold
Add event handling to open internal links in new tab by middle clicking.
2900
        connect(page, SIGNAL(linkClicked(bool,int,qreal,qreal)), SLOT(on_pages_linkClicked(bool,int,qreal,qreal)));
360 by Adam Reichold
manual merge of future branch
2901
    }
976 by Adam Reichold
prepare internally for per-tab color inversion
2902
}
739.1.6 by Adam Reichold
make background color configurable as well
2903
976 by Adam Reichold
prepare internally for per-tab color inversion
2904
void DocumentView::prepareBackground()
2905
{
739.1.6 by Adam Reichold
make background color configurable as well
2906
    QColor backgroundColor;
2907
1046.1.41 by Adam Reichold
begin transition to the new settings class
2908
    if(s_settings->pageItem().decoratePages())
739.1.6 by Adam Reichold
make background color configurable as well
2909
    {
1046.1.41 by Adam Reichold
begin transition to the new settings class
2910
        backgroundColor = s_settings->pageItem().backgroundColor();
739.1.6 by Adam Reichold
make background color configurable as well
2911
    }
2912
    else
2913
    {
1046.1.41 by Adam Reichold
begin transition to the new settings class
2914
        backgroundColor = s_settings->pageItem().paperColor();
739.1.6 by Adam Reichold
make background color configurable as well
2915
1898.2.7 by Adam Reichold
Merge latest fixes and improvements from the parent branch and simplify the internal handling of the render flags within the document view.
2916
        if(invertColors())
739.1.6 by Adam Reichold
make background color configurable as well
2917
        {
2918
            backgroundColor.setRgb(~backgroundColor.rgb());
2919
        }
2110 by Adam Reichold
Merge invert lightness functionality.
2920
2921
        if(invertLightness())
739.1.6 by Adam Reichold
make background color configurable as well
2922
        {
2923
            backgroundColor.setRgb(~backgroundColor.rgb());
2924
        }
2108.1.2 by Johan Björklund
Name change to "Invert lightness" and other fixes
2925
    }
739.1.6 by Adam Reichold
make background color configurable as well
2926
1046.1.3 by Adam Reichold
simplify scene management
2927
    scene()->setBackgroundBrush(QBrush(backgroundColor));
739.1.6 by Adam Reichold
make background color configurable as well
2928
    m_thumbnailsScene->setBackgroundBrush(QBrush(backgroundColor));
360 by Adam Reichold
manual merge of future branch
2929
}
2930
2931
void DocumentView::prepareScene()
2932
{
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
2933
    // prepare render parameters and adjust scale factor
2934
2111 by Adam Reichold
Add setting to ignore logical DPI as it is reported incorrectly in some multi monitor setups.
2935
    RenderParam renderParam(scaleFactor(), rotation(), renderFlags());
1898.2.2 by Adam Reichold
Add a setting to trigger the background composition.
2936
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
2937
#if QT_VERSION >= QT_VERSION_CHECK(5,1,0)
2938
1898.1.19 by Adam Reichold
Simplify handling of the device pixel ratio setting.
2939
    if(s_settings->pageItem().useDevicePixelRatio())
2940
    {
2091 by Adam Reichold
Use QPaintDevice::devicePixelRatioF instead of devicePixelRatio if available to better fractional scaling.
2941
#if QT_VERSION >= QT_VERSION_CHECK(5,6,0)
2942
2943
        renderParam.setDevicePixelRatio(devicePixelRatioF());
2944
2945
#else
2946
1898.1.19 by Adam Reichold
Simplify handling of the device pixel ratio setting.
2947
        renderParam.setDevicePixelRatio(devicePixelRatio());
2091 by Adam Reichold
Use QPaintDevice::devicePixelRatioF instead of devicePixelRatio if available to better fractional scaling.
2948
2949
#endif // QT_VERSION
1898.1.19 by Adam Reichold
Simplify handling of the device pixel ratio setting.
2950
    }
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
2951
2952
#endif // QT_VERSION
360 by Adam Reichold
manual merge of future branch
2953
2111 by Adam Reichold
Add setting to ignore logical DPI as it is reported incorrectly in some multi monitor setups.
2954
    if(s_settings->pageItem().useLogicalDpi())
2955
    {
2956
        renderParam.setResolution(logicalDpiX(), logicalDpiY());
2957
    }
2958
1367 by Adam Reichold
calculate visible viewport area only once
2959
    const qreal visibleWidth = m_layout->visibleWidth(viewport()->width());
2960
    const qreal visibleHeight = m_layout->visibleHeight(viewport()->height());
2961
1371 by Adam Reichold
simplify scale factor calcuation code path
2962
    foreach(PageItem* page, m_pageItems)
360 by Adam Reichold
manual merge of future branch
2963
    {
1898.2.17 by Adam Reichold
Do not reuse the crop rectangle to compute the displayed width if it will be invalidated by changing the trim-margins flag.
2964
        const QSizeF displayedSize = page->displayedSize(renderParam);
1371 by Adam Reichold
simplify scale factor calcuation code path
2965
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
2966
        if(m_scaleMode == FitToPageWidthMode)
2967
        {
1898.2.17 by Adam Reichold
Do not reuse the crop rectangle to compute the displayed width if it will be invalidated by changing the trim-margins flag.
2968
            adjustScaleFactor(renderParam, visibleWidth / displayedSize.width());
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
2969
        }
2970
        else if(m_scaleMode == FitToPageSizeMode)
2971
        {
1898.2.17 by Adam Reichold
Do not reuse the crop rectangle to compute the displayed width if it will be invalidated by changing the trim-margins flag.
2972
            adjustScaleFactor(renderParam, qMin(visibleWidth / displayedSize.width(), visibleHeight / displayedSize.height()));
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
2973
        }
2974
2975
        page->setRenderParam(renderParam);
360 by Adam Reichold
manual merge of future branch
2976
    }
2977
2978
    // prepare layout
2979
2980
    qreal left = 0.0;
2981
    qreal right = 0.0;
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
2982
    qreal height = s_settings->documentView().pageSpacing();
360 by Adam Reichold
manual merge of future branch
2983
1686 by Adam Reichold
Merge page-numbers branch improving calculation of current page in continuous layouts.
2984
    m_layout->prepareLayout(m_pageItems, m_rightToLeftMode,
2985
                            left, right, height);
424 by Adam Reichold
fix a serious bug where the last page of a document with an odd number of pages would not be displayed in continuous two pages mode
2986
1046.1.3 by Adam Reichold
simplify scene management
2987
    scene()->setSceneRect(left, 0.0, right - left, height);
360 by Adam Reichold
manual merge of future branch
2988
}
2989
1881.1.10 by Adam Reichold
Add another flag to view preparation with indicates whether we force scrolling to resolve interactions between scroll-if-not-visible and trim-margins functions.
2990
void DocumentView::prepareView(qreal newLeft, qreal newTop, bool forceScroll, int scrollToPage)
360 by Adam Reichold
manual merge of future branch
2991
{
1881.1.1 by Adam Reichold
Try to keep relative page position when jumping to a new location without explicit page-relative coordinates.
2992
    const QRectF sceneRect = scene()->sceneRect();
2993
2994
    qreal top = sceneRect.top();
2995
    qreal height = sceneRect.height();
360 by Adam Reichold
manual merge of future branch
2996
2997
    int horizontalValue = 0;
2998
    int verticalValue = 0;
2999
1881.1.10 by Adam Reichold
Add another flag to view preparation with indicates whether we force scrolling to resolve interactions between scroll-if-not-visible and trim-margins functions.
3000
    scrollToPage = scrollToPage != 0 ? scrollToPage : m_currentPage;
1499 by Adam Reichold
Choose a simpler yet more general solution by determining the viewport origin in prepareView itself.
3001
1727 by Adam Reichold
Implement jump to click search result via extended dock.
3002
    const int highlightIsOnPage = m_currentResult.isValid() ? pageOfResult(m_currentResult) : 0;
1719 by Adam Reichold
Merge central search model.
3003
    const bool highlightCurrentThumbnail = s_settings->documentView().highlightCurrentThumbnail();
3004
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
3005
    for(int index = 0; index < m_pageItems.count(); ++index)
360 by Adam Reichold
manual merge of future branch
3006
    {
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
3007
        PageItem* page = m_pageItems.at(index);
360 by Adam Reichold
manual merge of future branch
3008
3009
        if(m_continuousMode)
3010
        {
3011
            page->setVisible(true);
3012
        }
3013
        else
3014
        {
1348.1.4 by Adam Reichold
actually remove layout implementation from document view and adjust document layout interface accordingly
3015
            if(m_layout->leftIndex(index) == m_currentPage - 1)
360 by Adam Reichold
manual merge of future branch
3016
            {
3017
                page->setVisible(true);
3018
1881.1.9 by Adam Reichold
Use the uncropped bounding rect to compute page-relative positions.
3019
                const QRectF boundingRect = page->boundingRect().translated(page->pos());
3020
1046.1.41 by Adam Reichold
begin transition to the new settings class
3021
                top = boundingRect.top() - s_settings->documentView().pageSpacing();
3022
                height = boundingRect.height() + 2.0 * s_settings->documentView().pageSpacing();
360 by Adam Reichold
manual merge of future branch
3023
            }
3024
            else
3025
            {
3026
                page->setVisible(false);
461 by Adam Reichold
make sure viewport culling happens in non-continuous mode
3027
476 by Adam Reichold
redone threading in the rendering as prefetching was introducing race conditions, changed to a more robust signals-based design
3028
                page->cancelRender();
360 by Adam Reichold
manual merge of future branch
3029
            }
3030
        }
3031
1881.1.10 by Adam Reichold
Add another flag to view preparation with indicates whether we force scrolling to resolve interactions between scroll-if-not-visible and trim-margins functions.
3032
        if(index == scrollToPage - 1)
1499 by Adam Reichold
Choose a simpler yet more general solution by determining the viewport origin in prepareView itself.
3033
        {
1881.1.9 by Adam Reichold
Use the uncropped bounding rect to compute page-relative positions.
3034
            const QRectF boundingRect = page->uncroppedBoundingRect().translated(page->pos());
3035
1881.1.1 by Adam Reichold
Try to keep relative page position when jumping to a new location without explicit page-relative coordinates.
3036
            horizontalValue = qFloor(boundingRect.left() + newLeft * boundingRect.width());
3037
            verticalValue = qFloor(boundingRect.top() + newTop * boundingRect.height());
1499 by Adam Reichold
Choose a simpler yet more general solution by determining the viewport origin in prepareView itself.
3038
        }
3039
1719 by Adam Reichold
Merge central search model.
3040
        if(index == highlightIsOnPage - 1)
360 by Adam Reichold
manual merge of future branch
3041
        {
1527 by Adam Reichold
Merge redundant ifs using shortcut evaluation.
3042
            m_highlight->setPos(page->pos());
3043
            m_highlight->setTransform(page->transform());
546 by Adam Reichold
large change implementing 'two pages with cover' layout mode
3044
1527 by Adam Reichold
Merge redundant ifs using shortcut evaluation.
3045
            page->stackBefore(m_highlight);
360 by Adam Reichold
manual merge of future branch
3046
        }
1113 by Adam Reichold
add setting and implementation to highlight current thumbnail
3047
1687 by Adam Reichold
Improve naming of thumbnail highlighting Boolean property.
3048
        m_thumbnailItems.at(index)->setHighlighted(highlightCurrentThumbnail && (index == m_currentPage - 1));
360 by Adam Reichold
manual merge of future branch
3049
    }
3050
1881.1.1 by Adam Reichold
Try to keep relative page position when jumping to a new location without explicit page-relative coordinates.
3051
    setSceneRect(sceneRect.left(), top, sceneRect.width(), height);
360 by Adam Reichold
manual merge of future branch
3052
1900 by Adam Reichold
Rename the scroll-if-not-visible setting to minimal scrolling and document it in the online help.
3053
    if(!forceScroll && s_settings->documentView().minimalScrolling())
1881.1.4 by Adam Reichold
Add setting to scroll only if the target value is not yet visible.
3054
    {
3055
        setValueIfNotVisible(horizontalScrollBar(), horizontalValue);
3056
        setValueIfNotVisible(verticalScrollBar(), verticalValue);
3057
    }
3058
    else
3059
    {
3060
        horizontalScrollBar()->setValue(horizontalValue);
3061
        verticalScrollBar()->setValue(verticalValue);
3062
    }
565 by Adam Reichold
remove rendering artifacts when zooming out by explicit viewport update
3063
3064
    viewport()->update();
360 by Adam Reichold
manual merge of future branch
3065
}
3066
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3067
void DocumentView::prepareThumbnailsScene()
3068
{
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
3069
    // prepare render parameters and adjust scale factor
3070
2111 by Adam Reichold
Add setting to ignore logical DPI as it is reported incorrectly in some multi monitor setups.
3071
    RenderParam renderParam(scaleFactor(), rotation(), renderFlags());
1898.2.2 by Adam Reichold
Add a setting to trigger the background composition.
3072
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
3073
#if QT_VERSION >= QT_VERSION_CHECK(5,1,0)
3074
1898.1.19 by Adam Reichold
Simplify handling of the device pixel ratio setting.
3075
    if(s_settings->pageItem().useDevicePixelRatio())
3076
    {
2091 by Adam Reichold
Use QPaintDevice::devicePixelRatioF instead of devicePixelRatio if available to better fractional scaling.
3077
#if QT_VERSION >= QT_VERSION_CHECK(5,6,0)
3078
3079
        renderParam.setDevicePixelRatio(devicePixelRatioF());
3080
3081
#else
3082
1898.1.19 by Adam Reichold
Simplify handling of the device pixel ratio setting.
3083
        renderParam.setDevicePixelRatio(devicePixelRatio());
2091 by Adam Reichold
Use QPaintDevice::devicePixelRatioF instead of devicePixelRatio if available to better fractional scaling.
3084
3085
#endif // QT_VERSION
1898.1.19 by Adam Reichold
Simplify handling of the device pixel ratio setting.
3086
    }
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
3087
3088
#endif // QT_VERSION
3089
2111 by Adam Reichold
Add setting to ignore logical DPI as it is reported incorrectly in some multi monitor setups.
3090
    if(s_settings->pageItem().useLogicalDpi())
3091
    {
3092
        renderParam.setResolution(logicalDpiX(), logicalDpiY());
3093
    }
3094
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
3095
    const qreal thumbnailSize = s_settings->documentView().thumbnailSize();
1147 by Adam Reichold
begin to make local variables immutable by default
3096
    const qreal thumbnailSpacing = s_settings->documentView().thumbnailSpacing();
1046.1.41 by Adam Reichold
begin transition to the new settings class
3097
1923.1.1 by Adam Reichold
Make it possible to dynamically adjust the thumbnail size w.r.t. to the first viewport they are visible in.
3098
    qreal visibleWidth = Defaults::DocumentView::thumbnailSize();
3099
    qreal visibleHeight = Defaults::DocumentView::thumbnailSize();
3100
1923.1.4 by Adam Reichold
Communicate the thumbnails viewport size via an explicit property to have more flexibility in the future to decide which viewport determines scaling.
3101
    if(!m_thumbnailsViewportSize.isNull())
1923.1.1 by Adam Reichold
Make it possible to dynamically adjust the thumbnail size w.r.t. to the first viewport they are visible in.
3102
    {
1923.1.4 by Adam Reichold
Communicate the thumbnails viewport size via an explicit property to have more flexibility in the future to decide which viewport determines scaling.
3103
        visibleWidth = m_thumbnailsViewportSize.width() - 3.0 * thumbnailSpacing;
3104
        visibleHeight = m_thumbnailsViewportSize.height() - 3.0 * thumbnailSpacing;
1923.1.1 by Adam Reichold
Make it possible to dynamically adjust the thumbnail size w.r.t. to the first viewport they are visible in.
3105
    }
3106
3107
    foreach(ThumbnailItem* page, m_thumbnailItems)
3108
    {
3109
        const QSizeF displayedSize = page->displayedSize(renderParam);
3110
1923.1.2 by Adam Reichold
Allow fit-to-width as the special zero value of the thumbnail size in the settings dialog.
3111
        if(thumbnailSize != 0.0)
1923.1.1 by Adam Reichold
Make it possible to dynamically adjust the thumbnail size w.r.t. to the first viewport they are visible in.
3112
        {
3113
            adjustScaleFactor(renderParam, qMin(thumbnailSize / displayedSize.width(), thumbnailSize / displayedSize.height()));
3114
        }
3115
        else
3116
        {
3117
            if(m_thumbnailsOrientation == Qt::Vertical)
3118
            {
3119
                adjustScaleFactor(renderParam, visibleWidth / displayedSize.width());
3120
            }
3121
            else
3122
            {
3123
                adjustScaleFactor(renderParam, (visibleHeight - page->textHeight()) / displayedSize.height());
3124
            }
3125
        }
3126
3127
        page->setRenderParam(renderParam);
3128
    }
3129
3130
    // prepare layout
3131
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3132
    qreal left = 0.0;
1209 by Adam Reichold
make thumbnails layout orientation adjust according to dock orientation
3133
    qreal right = m_thumbnailsOrientation == Qt::Vertical ? 0.0 : thumbnailSpacing;
3134
    qreal top = 0.0;
3135
    qreal bottom = m_thumbnailsOrientation == Qt::Vertical ? thumbnailSpacing : 0.0;
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3136
1147 by Adam Reichold
begin to make local variables immutable by default
3137
    const bool limitThumbnailsToResults = s_settings->documentView().limitThumbnailsToResults();
1134 by Adam Reichold
do some local optimizations
3138
1046.1.6 by Adam Reichold
correctly remove owning semantics from page item class and make limiting of thumbnails configurable internally
3139
    for(int index = 0; index < m_thumbnailItems.count(); ++index)
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3140
    {
1713 by Adam Reichold
Just update the thumbnail text instead of reconstruction.
3141
        ThumbnailItem* page = m_thumbnailItems.at(index);
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3142
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
3143
        // prepare visibility
3144
1719 by Adam Reichold
Merge central search model.
3145
        if(limitThumbnailsToResults && s_searchModel->hasResults(this) && !s_searchModel->hasResultsOnPage(this, index + 1))
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3146
        {
3147
            page->setVisible(false);
3148
1046.1.9 by Adam Reichold
cancel thumbnail render if invisible clearing pixmap memory
3149
            page->cancelRender();
3150
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3151
            continue;
3152
        }
3153
3154
        page->setVisible(true);
3155
1898.1.11 by Adam Reichold
Change layout algorithm so that page items share as much render parameters as possible.
3156
        // prepare position
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3157
1147 by Adam Reichold
begin to make local variables immutable by default
3158
        const QRectF boundingRect = page->boundingRect();
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3159
1209 by Adam Reichold
make thumbnails layout orientation adjust according to dock orientation
3160
        if(m_thumbnailsOrientation == Qt::Vertical)
3161
        {
3162
            page->setPos(-boundingRect.left() - 0.5 * boundingRect.width(), bottom - boundingRect.top());
3163
3164
            left = qMin(left, -0.5f * boundingRect.width() - thumbnailSpacing);
3165
            right = qMax(right, 0.5f * boundingRect.width() + thumbnailSpacing);
3166
            bottom += boundingRect.height() + thumbnailSpacing;
3167
        }
3168
        else
3169
        {
3170
            page->setPos(right - boundingRect.left(), -boundingRect.top() - 0.5 * boundingRect.height());
3171
3172
            top = qMin(top, -0.5f * boundingRect.height() - thumbnailSpacing);
3173
            bottom = qMax(bottom, 0.5f * boundingRect.height() + thumbnailSpacing);
3174
            right += boundingRect.width() + thumbnailSpacing;
3175
        }
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3176
    }
3177
1209 by Adam Reichold
make thumbnails layout orientation adjust according to dock orientation
3178
    m_thumbnailsScene->setSceneRect(left, top, right - left, bottom - top);
1046.1.4 by Adam Reichold
limit visible thumbnails to search results
3179
}
3180
1164 by Adam Reichold
refactor highlight setup and use in search and for temporary highlights
3181
void DocumentView::prepareHighlight(int index, const QRectF& rect)
360 by Adam Reichold
manual merge of future branch
3182
{
1164 by Adam Reichold
refactor highlight setup and use in search and for temporary highlights
3183
    PageItem* page = m_pageItems.at(index);
3184
3185
    m_highlight->setPos(page->pos());
3186
    m_highlight->setTransform(page->transform());
3187
3188
    m_highlight->setRect(rect.normalized());
3189
    m_highlight->setBrush(QBrush(s_settings->pageItem().highlightColor()));
3190
3191
    page->stackBefore(m_highlight);
3192
3193
    m_highlight->setVisible(true);
3194
2041.2.9 by Adam Reichold
Instead of disconnecting and reconnecting slots to avoid redundant updates, block the signle relevant slot using a simple flag variable and an RAII helper.
3195
    {
3196
        VerticalScrollBarChangedBlocker verticalScrollBarChangedBlocker(this);
3197
3198
        centerOn(m_highlight);
3199
    }
1133 by Adam Reichold
instead of a local update, force a viewport update
3200
3201
    viewport()->update();
360 by Adam Reichold
manual merge of future branch
3202
}
1267 by Adam Reichold
fix getting an iterator to the previous results against wrapping and not being at end, i.e. do try to compute 'begin() - 1'
3203
1720 by Adam Reichold
Factor out some redundant code from the find slots of the document view.
3204
void DocumentView::checkResult()
3205
{
1727 by Adam Reichold
Implement jump to click search result via extended dock.
3206
    if(m_currentResult.isValid() && m_layout->currentPage(pageOfResult(m_currentResult)) != m_currentPage)
1720 by Adam Reichold
Factor out some redundant code from the find slots of the document view.
3207
    {
3208
        m_currentResult = QModelIndex();
3209
    }
3210
}
3211
3212
void DocumentView::applyResult()
3213
{
3214
    if(m_currentResult.isValid())
3215
    {
1727 by Adam Reichold
Implement jump to click search result via extended dock.
3216
        const int page = pageOfResult(m_currentResult);
3217
        const QRectF rect = rectOfResult(m_currentResult);
1720 by Adam Reichold
Factor out some redundant code from the find slots of the document view.
3218
3219
        jumpToPage(page);
3220
3221
        prepareHighlight(page - 1, rect);
3222
    }
3223
    else
3224
    {
3225
        m_highlight->setVisible(false);
3226
    }
3227
}
3228
1518 by Adam Reichold
Make proper use of application and anonymous namespaces and fix a few header guards.
3229
} // qpdfview