PDF highlighting support
[pykit.git] / PDFWidget.cc
1 // $Id$
2 //
3 // Copyright (C) 2010
4 //     Stefan Bund <info@j32.de>
5
6 /** \file
7     \brief PDFWidget non-inline non-template implementation */
8
9 #include "PDFWidget.hh"
10 //#include "PDFWidget.ih"
11
12 // Custom includes
13 #include <iostream>
14 #include <boost/foreach.hpp>
15 #include <QNetworkRequest>
16 #include <QNetworkReply>
17 #include <QKeyEvent>
18 #include <QWebView>
19 #include <QWebFrame>
20 #include <QApplication>
21 #include <QClipboard>
22
23 //#include "PDFWidget.mpp"
24 #define prefix_
25 ///////////////////////////////cc.p////////////////////////////////////////
26
27 prefix_ pykit::PDFWidget::PDFWidget(QString const & id, QNetworkAccessManager * manager,
28                                     QWidget * parent)
29     : QLabel(parent), id_ (id), manager_ (manager), currentPage_ (0), rubberBand_ (0)
30
31 {
32     QWebView * webView (dynamic_cast<QWebView*>(parent));
33     if (webView && !id_.isEmpty())
34         webView->page()->mainFrame()->addToJavaScriptWindowObject(id_,this);
35 }
36
37 prefix_ pykit::PDFWidget::PDFWidget(QString const & id, QString const & document,
38                                     QNetworkAccessManager * manager, QWidget * parent)
39     : QLabel(parent), id_ (id), manager_ (manager), currentPage_ (0), rubberBand_ (0)
40
41 {
42     setFocusPolicy(Qt::WheelFocus);
43     document_.reset(Poppler::Document::load(document));
44     QWebView * webView (dynamic_cast<QWebView*>(parent));
45     if (webView && !id_.isEmpty())
46         webView->page()->mainFrame()->addToJavaScriptWindowObject(id_,this);
47     documentSetup();
48 }
49
50 prefix_ pykit::PDFWidget::~PDFWidget()
51 {
52     if (rubberBand_)
53         delete rubberBand_;
54 }
55
56
57 prefix_ void pykit::PDFWidget::load(QUrl const & url)
58 {
59     QNetworkRequest request (url);
60     QNetworkReply * reply (manager_->get(request));
61     connect(reply, SIGNAL(finished()), this, SLOT(netLoadDocument()));
62 }
63
64 prefix_ void pykit::PDFWidget::resizeEvent(QResizeEvent *)
65 {
66     if (! document_)
67         return;
68     QSizeF pageSize (document_->page(currentPage_)->pageSizeF());
69     double n = 72.0 * width() / pageSize.width();
70     if (n != dpi_) {
71         dpi_ = n;
72         showPage();
73     }
74 }
75
76 prefix_ void pykit::PDFWidget::mousePressEvent(QMouseEvent * event)
77 {
78     origin_ = event->pos();
79     if (! rubberBand_)
80         rubberBand_ = new QRubberBand(QRubberBand::Rectangle, this);
81     rubberBand_->setGeometry(QRect(origin_, QSize()));
82     rubberBand_->show();
83 }
84
85 prefix_ void pykit::PDFWidget::mouseMoveEvent(QMouseEvent * event)
86 {
87     if (rubberBand_)
88         rubberBand_->setGeometry(QRect(origin_, event->pos()).normalized());
89 }
90
91 prefix_ void pykit::PDFWidget::mouseReleaseEvent(QMouseEvent *)
92 {
93     if (rubberBand_) {
94         QMatrix matrix (dpi_ / 72.0, 0, 0, dpi_ / 72.0, 0, 0);
95         QRectF rect (matrix.inverted().mapRect(QRect(rubberBand_->pos(), rubberBand_->size())));
96         QString text = document_->page(currentPage_)->text(rect);
97         if (! text.isEmpty())
98             QApplication::clipboard()->setText(text);
99     }
100 }
101
102 prefix_ void pykit::PDFWidget::netLoadDocument()
103 {
104     QNetworkReply * reply = static_cast<QNetworkReply*>(sender());
105     if (reply->error() != QNetworkReply::NoError)
106         return;
107     QByteArray data (reply->read(reply->size()));
108     document_.reset(Poppler::Document::loadFromData(data));
109     documentSetup();
110     reply->deleteLater();
111 }
112
113 prefix_ void pykit::PDFWidget::documentSetup()
114 {
115     if (! document_)
116         return;
117     document_->setRenderHint(Poppler::Document::Antialiasing, true);
118     document_->setRenderHint(Poppler::Document::TextAntialiasing, true);
119     document_->setRenderHint(Poppler::Document::TextHinting, false);
120     resizeEvent(0);
121     showPage();
122 }
123
124 prefix_ void pykit::PDFWidget::highlightString(QString const & str)
125 {
126     QRectF highlightArea;
127     Poppler::Page::SearchDirection dir (Poppler::Page::FromTop);
128     while (document_->page(currentPage_)->search(str, highlightArea, dir,
129                                                  Poppler::Page::CaseInsensitive)) {
130         highlightAreas_.push_back(highlightArea);
131         dir = Poppler::Page::NextResult;
132     }
133 }
134
135 prefix_ void pykit::PDFWidget::showPage()
136 {
137     if (! document_)
138         return;
139     QImage image (document_->page(currentPage_)->renderToImage(
140                       dpi_, dpi_, 0, 0, width(), height()));
141     QMatrix matrix (dpi_ / 72.0, 0, 0, dpi_ / 72.0, 0, 0);
142
143     BOOST_FOREACH(QRectF const & highlightArea, highlightAreas_) {
144         QRect highlightRect = matrix.mapRect(highlightArea).toRect();
145         highlightRect.adjust(-2, -2, 2, 2);
146         QImage highlight = image.copy(highlightRect);
147         QPainter painter;
148         painter.begin(&image);
149         painter.fillRect(image.rect(), QColor(0, 0, 0, 32));
150         painter.drawImage(highlightRect, highlight);
151         painter.end();
152     }
153
154     setPixmap(QPixmap::fromImage(image));
155 }
156
157 ///////////////////////////////cc.e////////////////////////////////////////
158 #undef prefix_
159 //#include "PDFWidget.mpp"
160
161 \f
162 // Local Variables:
163 // mode: c++
164 // fill-column: 100
165 // comment-column: 40
166 // c-file-style: "j32"
167 // indent-tabs-mode: nil
168 // ispell-local-dictionary: "american"
169 // compile-command: "make"
170 // End: