source: terepaima/terepaima-0.4.16/sources/djvumodel.cpp

desarrollostretch
Last change on this file was 1f4adec, checked in by aosorio <aosorio@…>, 8 years ago

Agregado proyecto base, esto luego del dh_make -f

  • Property mode set to 100644
File size: 23.4 KB
Line 
1/*
2
3Copyright 2014 S. Razi Alavizadeh
4Copyright 2013-2014 Adam Reichold
5Copyright 2013 Alexander Volkov
6
7This file is part of qpdfview.
8
9The implementation is based on KDjVu by Pino Toscano.
10
11qpdfview is free software: you can redistribute it and/or modify
12it under the terms of the GNU General Public License as published by
13the Free Software Foundation, either version 2 of the License, or
14(at your option) any later version.
15
16qpdfview is distributed in the hope that it will be useful,
17but WITHOUT ANY WARRANTY; without even the implied warranty of
18MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19GNU General Public License for more details.
20
21You should have received a copy of the GNU General Public License
22along with qpdfview.  If not, see <http://www.gnu.org/licenses/>.
23
24*/
25
26#include "djvumodel.h"
27
28#include <cstdio>
29
30#include <QFile>
31#include <qmath.h>
32
33#include <libdjvu/ddjvuapi.h>
34#include <libdjvu/miniexp.h>
35
36#define LOCK_PAGE QMutexLocker mutexLocker(&m_parent->m_mutex);
37#define LOCK_DOCUMENT QMutexLocker mutexLocker(&m_mutex);
38
39#if DDJVUAPI_VERSION < 23
40
41#define LOCK_PAGE_GLOBAL QMutexLocker globalMutexLocker(m_parent->m_globalMutex);
42#define LOCK_DOCUMENT_GLOBAL QMutexLocker globalMutexLocker(m_globalMutex);
43
44#else
45
46#define LOCK_PAGE_GLOBAL
47#define LOCK_DOCUMENT_GLOBAL
48
49#endif // DDJVUAPI_VERSION
50
51namespace
52{
53
54using namespace qpdfview;
55using namespace qpdfview::Model;
56
57inline miniexp_t miniexp_cadddr(miniexp_t exp)
58{
59    return miniexp_cadr(miniexp_cddr(exp));
60}
61
62inline miniexp_t miniexp_caddddr(miniexp_t exp)
63{
64    return miniexp_caddr(miniexp_cddr(exp));
65}
66
67inline miniexp_t skip(miniexp_t exp, int offset)
68{
69    while(offset-- > 0)
70    {
71        exp = miniexp_cdr(exp);
72    }
73
74    return exp;
75}
76
77void clearMessageQueue(ddjvu_context_t* context, bool wait)
78{
79    if(wait)
80    {
81        ddjvu_message_wait(context);
82    }
83
84    while(true)
85    {
86        if(ddjvu_message_peek(context) != 0)
87        {
88            ddjvu_message_pop(context);
89        }
90        else
91        {
92            break;
93        }
94    }
95}
96
97void waitForMessageTag(ddjvu_context_t* context, ddjvu_message_tag_t tag)
98{
99    ddjvu_message_wait(context);
100
101    while(true)
102    {
103        ddjvu_message_t* message = ddjvu_message_peek(context);
104
105        if(message != 0)
106        {
107            if(message->m_any.tag == tag)
108            {
109                break;
110            }
111
112            ddjvu_message_pop(context);
113        }
114        else
115        {
116            break;
117        }
118    }
119}
120
121QPainterPath loadLinkBoundary(const QString& type, miniexp_t boundaryExp, const QSizeF& size)
122{
123    QPainterPath boundary;
124
125    const int count = miniexp_length(boundaryExp);
126
127    if(count == 4 && (type == QLatin1String("rect") || type == QLatin1String("oval")))
128    {
129        QPoint p(miniexp_to_int(miniexp_car(boundaryExp)), miniexp_to_int(miniexp_cadr(boundaryExp)));
130        QSize s(miniexp_to_int(miniexp_caddr(boundaryExp)), miniexp_to_int(miniexp_cadddr(boundaryExp)));
131
132        p.setY(size.height() - s.height() - p.y());
133
134        const QRectF r(p, s);
135
136        if(type == QLatin1String("rect"))
137        {
138            boundary.addRect(r);
139        }
140        else
141        {
142            boundary.addEllipse(r);
143        }
144    }
145    else if(count > 0 && count % 2 == 0 && type == QLatin1String("poly"))
146    {
147        QPolygon polygon;
148
149        for(int index = 0; index < count; index += 2)
150        {
151            QPoint p(miniexp_to_int(miniexp_nth(index, boundaryExp)), miniexp_to_int(miniexp_nth(index + 1, boundaryExp)));
152
153            p.setY(size.height() - p.y());
154
155            polygon << p;
156        }
157
158        boundary.addPolygon(polygon);
159    }
160
161    return QTransform::fromScale(1.0 / size.width(), 1.0 / size.height()).map(boundary);
162}
163
164Link* loadLinkTarget(const QPainterPath& boundary, miniexp_t targetExp, int index, const QHash< QString, int >& indexByName)
165{
166    QString target;
167
168    if(miniexp_stringp(targetExp))
169    {
170        target = QString::fromUtf8(miniexp_to_str(targetExp));
171    }
172    else if(miniexp_length(targetExp) == 3 && qstrcmp(miniexp_to_name(miniexp_car(targetExp)), "url") == 0)
173    {
174        target = QString::fromUtf8(miniexp_to_str(miniexp_cadr(targetExp)));
175    }
176
177    if(target.isEmpty())
178    {
179        return 0;
180    }
181
182    if(target.at(0) == QLatin1Char('#'))
183    {
184        target.remove(0, 1);
185
186        bool ok = false;
187        int targetPage = target.toInt(&ok);
188
189        if(!ok)
190        {
191            if(indexByName.contains(target))
192            {
193                targetPage = indexByName[target] + 1;
194            }
195            else
196            {
197                return 0;
198            }
199        }
200        else
201        {
202            if(target.at(0) == QLatin1Char('+') || target.at(0) == QLatin1Char('-'))
203            {
204                targetPage += index + 1;
205            }
206        }
207
208        return new Link(boundary, targetPage);
209    }
210    else
211    {
212        return new Link(boundary, target);
213    }
214}
215
216QList< Link* > loadLinks(miniexp_t linkExp, const QSizeF& size, int index, const QHash< QString, int >& indexByName)
217{
218    QList< Link* > links;
219
220    for(miniexp_t linkItem = miniexp_nil; miniexp_consp(linkExp); linkExp = miniexp_cdr(linkExp))
221    {
222        linkItem = miniexp_car(linkExp);
223
224        if(miniexp_length(linkItem) < 4 || qstrcmp(miniexp_to_name(miniexp_car(linkItem)), "maparea") != 0)
225        {
226            continue;
227        }
228
229        miniexp_t targetExp = miniexp_cadr(linkItem);
230        miniexp_t boundaryExp = miniexp_cadddr(linkItem);
231
232        if(!miniexp_symbolp(miniexp_car(boundaryExp)))
233        {
234            continue;
235        }
236
237        const QString type = QString::fromUtf8(miniexp_to_name(miniexp_car(boundaryExp)));
238
239        if(type == QLatin1String("rect") || type == QLatin1String("oval") || type == QLatin1String("poly"))
240        {
241            QPainterPath boundary = loadLinkBoundary(type, miniexp_cdr(boundaryExp), size);
242
243            if(!boundary.isEmpty())
244            {
245                Link* link = loadLinkTarget(boundary, targetExp, index, indexByName);
246
247                if(link != 0)
248                {
249                    links.append(link);
250                }
251            }
252        }
253    }
254
255    return links;
256}
257
258QString loadText(miniexp_t textExp, const QSizeF& size, const QRectF& rect)
259{
260    if(miniexp_length(textExp) < 6 && !miniexp_symbolp(miniexp_car(textExp)))
261    {
262        return QString();
263    }
264
265    const int xmin = miniexp_to_int(miniexp_cadr(textExp));
266    const int ymin = miniexp_to_int(miniexp_caddr(textExp));
267    const int xmax = miniexp_to_int(miniexp_cadddr(textExp));
268    const int ymax = miniexp_to_int(miniexp_caddddr(textExp));
269
270    if(rect.intersects(QRect(xmin, size.height() - ymax, xmax - xmin, ymax - ymin)))
271    {
272        const QString type = QString::fromUtf8(miniexp_to_name(miniexp_car(textExp)));
273
274        if(type == QLatin1String("word"))
275        {
276            return QString::fromUtf8(miniexp_to_str(miniexp_nth(5, textExp)));
277        }
278        else
279        {
280            QStringList text;
281
282            textExp = skip(textExp, 5);
283
284            for(miniexp_t textItem = miniexp_nil; miniexp_consp(textExp); textExp = miniexp_cdr(textExp))
285            {
286                textItem = miniexp_car(textExp);
287
288                text.append(loadText(textItem, size, rect));
289            }
290
291            return type == QLatin1String("line") ? text.join(" ") : text.join("\n");
292        }
293    }
294
295    return QString();
296}
297
298QList< QRectF > findText(miniexp_t pageTextExp, const QSizeF& size, const QTransform& transform, const QStringList& words, bool matchCase, bool wholeWords)
299{
300    if(words.isEmpty())
301    {
302        return QList< QRectF >();
303    }
304
305    const Qt::CaseSensitivity caseSensitivity = matchCase ? Qt::CaseSensitive : Qt::CaseInsensitive;
306
307    QRectF result;
308    int wordIndex = 0;
309
310    QList< miniexp_t > texts;
311    QList< QRectF > results;
312
313    texts.append(pageTextExp);
314
315    while(!texts.isEmpty())
316    {
317        miniexp_t textExp = texts.takeFirst();
318
319        if(miniexp_length(textExp) < 6 || !miniexp_symbolp(miniexp_car(textExp)))
320        {
321            continue;
322        }
323
324        const QString type = QString::fromUtf8(miniexp_to_name(miniexp_car(textExp)));
325
326        if(type == QLatin1String("word"))
327        {
328            const QString text = QString::fromUtf8(miniexp_to_str(miniexp_nth(5, textExp)));
329
330            int index = 0;
331
332            while((index = text.indexOf(words.at(wordIndex), index, caseSensitivity)) != -1)
333            {
334                const int nextIndex = index + words.at(wordIndex).length();
335
336                const bool wordBegins = index == 0 || !text.at(index - 1).isLetterOrNumber();
337                const bool wordEnds = nextIndex == text.length() || !text.at(nextIndex).isLetterOrNumber();
338
339                if(!wholeWords || (wordBegins && wordEnds))
340                {
341                    const int xmin = miniexp_to_int(miniexp_cadr(textExp));
342                    const int ymin = miniexp_to_int(miniexp_caddr(textExp));
343                    const int xmax = miniexp_to_int(miniexp_cadddr(textExp));
344                    const int ymax = miniexp_to_int(miniexp_caddddr(textExp));
345
346                    result = result.united(QRectF(xmin, size.height() - ymax, xmax - xmin, ymax - ymin));
347
348                    // Advance after partial match
349                    if(++wordIndex == words.size())
350                    {
351                        results.append(transform.mapRect(result));
352
353                        // Reset after full match
354                        result = QRectF();
355                        wordIndex = 0;
356                    }
357                }
358                else
359                {
360                    // Reset after malformed match
361                    result = QRectF();
362                    wordIndex = 0;
363                }
364
365                if((index = nextIndex) >= text.length())
366                {
367                    break;
368                }
369            }
370
371            if(index < 0)
372            {
373                // Reset after empty match
374                result = QRectF();
375                wordIndex = 0;
376            }
377        }
378        else
379        {
380            textExp = skip(textExp, 5);
381
382            for(miniexp_t textItem = miniexp_nil; miniexp_consp(textExp); textExp = miniexp_cdr(textExp))
383            {
384                textItem = miniexp_car(textExp);
385
386                texts.append(textItem);
387            }
388        }
389    }
390
391    return results;
392}
393
394void loadOutline(miniexp_t outlineExp, QStandardItem* parent, const QHash< QString, int >& indexByName)
395{
396    for(miniexp_t outlineItem = miniexp_nil; miniexp_consp(outlineExp); outlineExp = miniexp_cdr(outlineExp))
397    {
398        outlineItem = miniexp_car(outlineExp);
399
400        if(miniexp_length(outlineItem) < 2 || !miniexp_stringp(miniexp_car(outlineItem)) || !miniexp_stringp(miniexp_cadr(outlineItem)))
401        {
402            continue;
403        }
404
405        const QString title = QString::fromUtf8(miniexp_to_str(miniexp_car(outlineItem)));
406        QString destination = QString::fromUtf8(miniexp_to_str(miniexp_cadr(outlineItem)));
407
408        if(!title.isEmpty() && !destination.isEmpty())
409        {
410            if(destination.at(0) == QLatin1Char('#'))
411            {
412                destination.remove(0,1);
413
414                bool ok = false;
415                int destinationPage = destination.toInt(&ok);
416
417                if(!ok)
418                {
419                    if(indexByName.contains(destination))
420                    {
421                        destinationPage = indexByName[destination] + 1;
422                    }
423                    else
424                    {
425                        continue;
426                    }
427                }
428
429                QStandardItem* item = new QStandardItem(title);
430                item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
431
432                item->setData(destinationPage, Document::PageRole);
433                item->setData(qQNaN(), Document::LeftRole);
434                item->setData(qQNaN(), Document::TopRole);
435
436                QStandardItem* pageItem = item->clone();
437                pageItem->setText(QString::number(destinationPage));
438                pageItem->setTextAlignment(Qt::AlignRight);
439
440                parent->appendRow(QList< QStandardItem* >() << item << pageItem);
441
442                if(miniexp_length(outlineItem) > 2)
443                {
444                    loadOutline(skip(outlineItem, 2), item, indexByName);
445                }
446            }
447        }
448    }
449}
450
451void loadProperties(miniexp_t annoExp, QStandardItemModel* model)
452{
453    for(miniexp_t annoItem = miniexp_nil; miniexp_consp(annoExp); annoExp = miniexp_cdr(annoExp))
454    {
455        annoItem = miniexp_car(annoExp);
456
457        if(miniexp_length(annoItem) < 2 || qstrcmp(miniexp_to_name(miniexp_car(annoItem)), "metadata") != 0)
458        {
459            continue;
460        }
461
462        annoItem = miniexp_cdr(annoItem);
463
464        for(miniexp_t keyValueItem = miniexp_nil; miniexp_consp(annoItem); annoItem = miniexp_cdr(annoItem))
465        {
466            keyValueItem = miniexp_car(annoItem);
467
468            if(miniexp_length(keyValueItem) != 2)
469            {
470                continue;
471            }
472
473            const QString key = QString::fromUtf8(miniexp_to_name(miniexp_car(keyValueItem)));
474            const QString value = QString::fromUtf8(miniexp_to_str(miniexp_cadr(keyValueItem)));
475
476            if(!key.isEmpty() && !value.isEmpty())
477            {
478                model->appendRow(QList< QStandardItem* >() << new QStandardItem(key) << new QStandardItem(value));
479            }
480        }
481    }
482}
483
484} // anonymous
485
486namespace qpdfview
487{
488
489namespace Model
490{
491
492DjVuPage::DjVuPage(const DjVuDocument* parent, int index, const ddjvu_pageinfo_t& pageinfo) :
493    m_parent(parent),
494    m_index(index),
495    m_size(pageinfo.width, pageinfo.height),
496    m_resolution(pageinfo.dpi)
497{
498}
499
500DjVuPage::~DjVuPage()
501{
502}
503
504QSizeF DjVuPage::size() const
505{
506    return 72.0 / m_resolution * m_size;
507}
508
509QImage DjVuPage::render(qreal horizontalResolution, qreal verticalResolution, Rotation rotation, const QRect& boundingRect) const
510{
511    LOCK_PAGE
512
513    ddjvu_page_t* page = ddjvu_page_create_by_pageno(m_parent->m_document, m_index);
514
515    if(page == 0)
516    {
517        return QImage();
518    }
519
520    ddjvu_status_t status;
521
522    while(true)
523    {
524        status = ddjvu_page_decoding_status(page);
525
526        if(status < DDJVU_JOB_OK)
527        {
528            clearMessageQueue(m_parent->m_context, true);
529        }
530        else
531        {
532            break;
533        }
534    }
535
536    if(status >= DDJVU_JOB_FAILED)
537    {
538        ddjvu_page_release(page);
539
540        return QImage();
541    }
542
543    switch(rotation)
544    {
545    default:
546    case RotateBy0:
547        ddjvu_page_set_rotation(page, DDJVU_ROTATE_0);
548        break;
549    case RotateBy90:
550        ddjvu_page_set_rotation(page, DDJVU_ROTATE_270);
551        break;
552    case RotateBy180:
553        ddjvu_page_set_rotation(page, DDJVU_ROTATE_180);
554        break;
555    case RotateBy270:
556        ddjvu_page_set_rotation(page, DDJVU_ROTATE_90);
557        break;
558    }
559
560    ddjvu_rect_t pagerect;
561
562    pagerect.x = 0;
563    pagerect.y = 0;
564
565    switch(rotation)
566    {
567    default:
568    case RotateBy0:
569    case RotateBy180:
570        pagerect.w = qRound(horizontalResolution / m_resolution * m_size.width());
571        pagerect.h = qRound(verticalResolution / m_resolution * m_size.height());
572        break;
573    case RotateBy90:
574    case RotateBy270:
575        pagerect.w = qRound(horizontalResolution / m_resolution * m_size.height());
576        pagerect.h = qRound(verticalResolution / m_resolution * m_size.width());
577        break;
578    }
579
580    ddjvu_rect_t renderrect;
581
582    if(boundingRect.isNull())
583    {
584        renderrect.x = pagerect.x;
585        renderrect.y = pagerect.y;
586        renderrect.w = pagerect.w;
587        renderrect.h = pagerect.h;
588    }
589    else
590    {
591        renderrect.x = boundingRect.x();
592        renderrect.y = boundingRect.y();
593        renderrect.w = boundingRect.width();
594        renderrect.h = boundingRect.height();
595    }
596
597    QImage image(renderrect.w, renderrect.h, QImage::Format_RGB32);
598
599    if(!ddjvu_page_render(page, DDJVU_RENDER_COLOR, &pagerect, &renderrect, m_parent->m_format, image.bytesPerLine(), reinterpret_cast< char* >(image.bits())))
600    {
601        image = QImage();
602    }
603
604    clearMessageQueue(m_parent->m_context, false);
605
606    ddjvu_page_release(page);
607
608    return image;
609}
610
611QList< Link* > DjVuPage::links() const
612{
613    LOCK_PAGE
614
615    miniexp_t pageAnnoExp = miniexp_nil;
616
617    {
618        LOCK_PAGE_GLOBAL
619
620        while(true)
621        {
622            pageAnnoExp = ddjvu_document_get_pageanno(m_parent->m_document, m_index);
623
624            if(pageAnnoExp == miniexp_dummy)
625            {
626                clearMessageQueue(m_parent->m_context, true);
627            }
628            else
629            {
630                break;
631            }
632        }
633    }
634
635    const QList< Link* > links = loadLinks(pageAnnoExp, m_size, m_index, m_parent->m_indexByName);
636
637    {
638        LOCK_PAGE_GLOBAL
639
640        ddjvu_miniexp_release(m_parent->m_document, pageAnnoExp);
641    }
642
643    return links;
644}
645
646QString DjVuPage::text(const QRectF& rect) const
647{
648    LOCK_PAGE
649
650    miniexp_t pageTextExp = miniexp_nil;
651
652    {
653        LOCK_PAGE_GLOBAL
654
655        while(true)
656        {
657            pageTextExp = ddjvu_document_get_pagetext(m_parent->m_document, m_index, "word");
658
659            if(pageTextExp == miniexp_dummy)
660            {
661                clearMessageQueue(m_parent->m_context, true);
662            }
663            else
664            {
665                break;
666            }
667        }
668    }
669
670    const QTransform transform = QTransform::fromScale(m_resolution / 72.0, m_resolution / 72.0);
671
672    const QString text = loadText(pageTextExp, m_size, transform.mapRect(rect)).simplified();
673
674    {
675        LOCK_PAGE_GLOBAL
676
677        ddjvu_miniexp_release(m_parent->m_document, pageTextExp);
678    }
679
680    return text.simplified();
681}
682
683QList< QRectF > DjVuPage::search(const QString& text, bool matchCase, bool wholeWords) const
684{
685    LOCK_PAGE
686
687    miniexp_t pageTextExp = miniexp_nil;
688
689    {
690        LOCK_PAGE_GLOBAL
691
692        while(true)
693        {
694            pageTextExp = ddjvu_document_get_pagetext(m_parent->m_document, m_index, "word");
695
696            if(pageTextExp == miniexp_dummy)
697            {
698                clearMessageQueue(m_parent->m_context, true);
699            }
700            else
701            {
702                break;
703            }
704        }
705    }
706
707    const QTransform transform = QTransform::fromScale(72.0 / m_resolution, 72.0 / m_resolution);
708    const QStringList words = text.split(QRegExp(QLatin1String("\\W+")), QString::SkipEmptyParts);
709
710    const QList< QRectF > results = findText(pageTextExp, m_size, transform, words, matchCase, wholeWords);
711
712    {
713        LOCK_PAGE_GLOBAL
714
715        ddjvu_miniexp_release(m_parent->m_document, pageTextExp);
716    }
717
718    return results;
719}
720
721DjVuDocument::DjVuDocument(QMutex* globalMutex, ddjvu_context_t* context, ddjvu_document_t* document) :
722    m_mutex(),
723    m_globalMutex(globalMutex),
724    m_context(context),
725    m_document(document),
726    m_format(0),
727    m_indexByName()
728{
729    unsigned int mask[] = {0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000};
730
731    m_format = ddjvu_format_create(DDJVU_FORMAT_RGBMASK32, 4, mask);
732    ddjvu_format_set_row_order(m_format, 1);
733    ddjvu_format_set_y_direction(m_format, 1);
734
735    prepareIndexByName();
736}
737
738DjVuDocument::~DjVuDocument()
739{
740    ddjvu_document_release(m_document);
741    ddjvu_context_release(m_context);
742    ddjvu_format_release(m_format);
743}
744
745int DjVuDocument::numberOfPages() const
746{
747    LOCK_DOCUMENT
748
749    return ddjvu_document_get_pagenum(m_document);
750}
751
752Page* DjVuDocument::page(int index) const
753{
754    LOCK_DOCUMENT
755
756    ddjvu_status_t status;
757    ddjvu_pageinfo_t pageinfo;
758
759    while(true)
760    {
761        status = ddjvu_document_get_pageinfo(m_document, index, &pageinfo);
762
763        if(status < DDJVU_JOB_OK)
764        {
765            clearMessageQueue(m_context, true);
766        }
767        else
768        {
769            break;
770        }
771    }
772
773    if(status >= DDJVU_JOB_FAILED)
774    {
775        return 0;
776    }
777
778    return new DjVuPage(this, index, pageinfo);
779}
780
781QStringList DjVuDocument::saveFilter() const
782{
783    return QStringList() << QLatin1String("DjVu (*.djvu *.djv)");
784}
785
786bool DjVuDocument::canSave() const
787{
788    return true;
789}
790
791bool DjVuDocument::save(const QString& filePath, bool withChanges) const
792{
793    Q_UNUSED(withChanges);
794
795    LOCK_DOCUMENT
796
797#ifdef _MSC_VER
798
799    FILE* file = _wfopen(reinterpret_cast< const wchar_t* >(filePath.utf16()), L"w+");
800
801#else
802
803    FILE* file = fopen(QFile::encodeName(filePath), "w+");
804
805#endif // _MSC_VER
806
807    if(file == 0)
808    {
809        return false;
810    }
811
812    ddjvu_job_t* job = ddjvu_document_save(m_document, file, 0, 0);
813
814    while(!ddjvu_job_done(job))
815    {
816        clearMessageQueue(m_context, true);
817    }
818
819    fclose(file);
820
821    return !ddjvu_job_error(job);
822}
823
824void DjVuDocument::loadOutline(QStandardItemModel* outlineModel) const
825{
826    Document::loadOutline(outlineModel);
827
828    LOCK_DOCUMENT
829
830    miniexp_t outlineExp = miniexp_nil;
831
832    {
833        LOCK_DOCUMENT_GLOBAL
834
835        while(true)
836        {
837            outlineExp = ddjvu_document_get_outline(m_document);
838
839            if(outlineExp == miniexp_dummy)
840            {
841                clearMessageQueue(m_context, true);
842            }
843            else
844            {
845                break;
846            }
847        }
848    }
849
850    if(miniexp_length(outlineExp) < 2 || qstrcmp(miniexp_to_name(miniexp_car(outlineExp)), "bookmarks") != 0)
851    {
852        return;
853    }
854
855    ::loadOutline(skip(outlineExp, 1), outlineModel->invisibleRootItem(), m_indexByName);
856
857    {
858        LOCK_DOCUMENT_GLOBAL
859
860        ddjvu_miniexp_release(m_document, outlineExp);
861    }
862}
863
864void DjVuDocument::loadProperties(QStandardItemModel* propertiesModel) const
865{
866    Document::loadProperties(propertiesModel);
867
868    LOCK_DOCUMENT
869
870    miniexp_t annoExp = miniexp_nil;
871
872    {
873        LOCK_DOCUMENT_GLOBAL
874
875        while(true)
876        {
877            annoExp = ddjvu_document_get_anno(m_document, TRUE);
878
879            if(annoExp == miniexp_dummy)
880            {
881                clearMessageQueue(m_context, true);
882            }
883            else
884            {
885                break;
886            }
887        }
888    }
889
890    ::loadProperties(annoExp, propertiesModel);
891
892    {
893        LOCK_DOCUMENT_GLOBAL
894
895        ddjvu_miniexp_release(m_document, annoExp);
896    }
897}
898
899void DjVuDocument::prepareIndexByName()
900{
901    for(int index = 0, count = ddjvu_document_get_filenum(m_document); index < count; ++index)
902    {
903        ddjvu_fileinfo_t fileinfo;
904
905        if(ddjvu_document_get_fileinfo(m_document, index, &fileinfo) != DDJVU_JOB_OK || fileinfo.type != 'P')
906        {
907            continue;
908        }
909
910        m_indexByName[QString::fromUtf8(fileinfo.id)] = m_indexByName[QString::fromUtf8(fileinfo.name)] = m_indexByName[QString::fromUtf8(fileinfo.title)] = fileinfo.pageno;
911    }
912}
913
914} // Model
915
916DjVuPlugin::DjVuPlugin(QObject* parent) : QObject(parent),
917    m_globalMutex()
918{
919    setObjectName("DjVuPlugin");
920}
921
922Model::Document* DjVuPlugin::loadDocument(const QString& filePath) const
923{
924    ddjvu_context_t* context = ddjvu_context_create("qpdfview");
925
926    if(context == 0)
927    {
928        return 0;
929    }
930
931#if DDJVUAPI_VERSION >= 19
932
933    ddjvu_document_t* document = ddjvu_document_create_by_filename_utf8(context, filePath.toUtf8(), FALSE);
934
935#else
936
937    ddjvu_document_t* document = ddjvu_document_create_by_filename(context, QFile::encodeName(filePath), FALSE);
938
939#endif // DDJVUAPI_VERSION
940
941    if(document == 0)
942    {
943        ddjvu_context_release(context);
944
945        return 0;
946    }
947
948    waitForMessageTag(context, DDJVU_DOCINFO);
949
950    if(ddjvu_document_decoding_error(document))
951    {
952        ddjvu_document_release(document);
953        ddjvu_context_release(context);
954
955        return 0;
956    }
957
958    return new Model::DjVuDocument(&m_globalMutex, context, document);
959}
960
961} // qpdfview
962
963#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
964
965Q_EXPORT_PLUGIN2(qpdfview_djvu, qpdfview::DjVuPlugin)
966
967#endif // QT_VERSION
Note: See TracBrowser for help on using the repository browser.