File indexing completed on 2024-04-28 05:38:14

0001 /***************************************************************************
0002  *  Copyright (C) 2009 by Renaud Guezennec                             *
0003  *   https://rolisteam.org/contact                   *
0004  *                                                                         *
0005  *   rolisteam is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
0019  ***************************************************************************/
0020 
0021 #include "pdfviewer.h"
0022 #include <QBuffer>
0023 #include <QDebug>
0024 #include <QMessageBox>
0025 #include <QPdfBookmarkModel>
0026 #include <QPdfDocument>
0027 #include <QPdfPageNavigator>
0028 #include <QPdfView>
0029 #include <QScrollBar>
0030 #include <QShortcut>
0031 #include <QtGui>
0032 #include <type_traits>
0033 
0034 #include "controller/view_controller/pdfcontroller.h"
0035 #include "customs/overlay.h"
0036 #include "ui_pdfviewer.h"
0037 
0038 #define MARGING 0
0039 #define ICON_SIZE 32
0040 
0041 Q_LOGGING_CATEGORY(MediaContainerPDF, "mediacontainer.pdf")
0042 
0043 PdfViewer::PdfViewer(PdfController* ctrl, QWidget* parent)
0044     : MediaContainer(ctrl, MediaContainer::ContainerType::PDFContainer, parent)
0045     , m_ui(new Ui::PdfViewer)
0046     , m_document(new QPdfDocument())
0047     , m_pdfCtrl(ctrl)
0048 {
0049     setObjectName("PdfViewer");
0050     setWindowIcon(QIcon::fromTheme("pdfLogo"));
0051     auto wid= new QWidget();
0052     m_ui->setupUi(wid);
0053     setWidget(wid);
0054 
0055     m_ui->m_view->setDocument(m_document.get());
0056 
0057     QPdfBookmarkModel* bookmarkModel= new QPdfBookmarkModel(this);
0058     m_ui->bookmarkView->setModel(bookmarkModel);
0059     bookmarkModel->setDocument(m_document.get());
0060 
0061     makeConnections();
0062     if(m_pdfCtrl)
0063     {
0064         if(!m_pdfCtrl->data().isEmpty())
0065         {
0066             auto buf= m_pdfCtrl->buffer();
0067             if(buf->open(QIODevice::ReadOnly))
0068                 m_document->load(buf);
0069         }
0070         else
0071             m_document->load(m_pdfCtrl->url().toLocalFile());
0072     }
0073 }
0074 
0075 PdfViewer::~PdfViewer() {}
0076 
0077 void PdfViewer::makeConnections()
0078 {
0079     m_ui->m_cropViewAct->setIcon(QIcon::fromTheme("crop"));
0080     m_ui->m_shareAct->setIcon(QIcon::fromTheme("share_doc"));
0081     m_ui->m_continuousAct->setIcon(QIcon::fromTheme("view-page-continuous"));
0082     m_ui->m_exportToMapAct->setIcon(QIcon::fromTheme("edit-copy"));
0083     m_ui->m_exportToImage->setIcon(QIcon::fromTheme("image-x-generic"));
0084     m_ui->m_extractTextAct->setIcon(QIcon::fromTheme("text"));
0085 
0086     m_ui->m_cropBtn->setDefaultAction(m_ui->m_cropViewAct);
0087     m_ui->m_shareBtn->setDefaultAction(m_ui->m_shareAct);
0088     m_ui->m_exportToMapBtn->setDefaultAction(m_ui->m_exportToMapAct);
0089     m_ui->m_exportToImageBtn->setDefaultAction(m_ui->m_exportToImage);
0090     m_ui->m_continuousBtn->setDefaultAction(m_ui->m_continuousAct);
0091 
0092     m_ui->m_extractTextBtn->setDefaultAction(m_ui->m_extractTextAct);
0093     m_ui->m_extractTextBtn->setVisible(false);
0094     m_ui->m_exportToImageBtn->setVisible(false);
0095 
0096     m_ui->m_zoomInBtn->setDefaultAction(m_ui->m_zoomInAct);
0097     m_ui->m_zoomOutBtn->setDefaultAction(m_ui->m_zoomOutAct);
0098 
0099     m_ui->m_nextPageBtn->setDefaultAction(m_ui->m_nextPageAct);
0100     m_ui->m_previousPageBtn->setDefaultAction(m_ui->m_previousPageAct);
0101 
0102     m_ui->m_exportToImage->setEnabled(false);
0103     m_ui->m_exportToMapAct->setEnabled(false);
0104     m_ui->m_extractTextAct->setEnabled(false);
0105 
0106     connect(m_ui->m_zoomLevel, &QComboBox::currentIndexChanged, this,
0107             [this]()
0108             {
0109                 auto i= m_ui->m_zoomLevel->currentIndex();
0110                 //, FitHeight, TwentyFiveZoom, FiftyZoom, SeventyFiveZoom, OneHundredZoom, OneHundredFitfyZoom,
0111                 // TwoHundredZoom};
0112                 if(i == FitWidth)
0113                 {
0114                     m_ui->m_view->setZoomMode(QPdfView::ZoomMode::FitToWidth);
0115                 }
0116                 else if(i == FitInView)
0117                 {
0118                     m_ui->m_view->setZoomMode(QPdfView::ZoomMode::FitInView);
0119                 }
0120                 else
0121                 {
0122                     m_ui->m_view->setZoomMode(QPdfView::ZoomMode::Custom);
0123 
0124                     static QHash<int, qreal> dataValue{{TwentyFiveZoom, 0.25},     {FiftyZoom, 0.5},
0125                                                        {SeventyFiveZoom, 0.75},    {OneHundredZoom, 1.0},
0126                                                        {OneHundredFitfyZoom, 1.5}, {TwoHundredZoom, 2.0}};
0127                     m_ui->m_view->setZoomFactor(dataValue.value(i));
0128                 }
0129             });
0130     connect(m_ui->m_zoomLevel, &QComboBox::currentTextChanged, this,
0131             [this](const QString& text)
0132             {
0133                 bool ok;
0134                 auto zoomlvl= static_cast<qreal>(text.toInt(&ok));
0135                 if(ok)
0136                 {
0137                     m_ui->m_view->setZoomFactor(zoomlvl / 100.0);
0138                 }
0139             });
0140 
0141     m_ui->m_zoomLevel->setValidator(new QIntValidator);
0142     connect(m_ui->m_continuousAct, &QAction::triggered, this,
0143             [this](bool continuous) {
0144                 m_ui->m_view->setPageMode(continuous ? QPdfView::PageMode::MultiPage : QPdfView::PageMode::SinglePage);
0145             });
0146 
0147     const auto& rect= geometry();
0148     m_ui->m_splitter->setSizes(
0149         QList{{static_cast<int>(rect.width() * 0.2), static_cast<int>(rect.width() * 0.8)}}); // QSplitter
0150     connect(m_ui->m_zoomInAct, &QAction::triggered, this, [this]() { m_pdfCtrl->zoomIn(); });
0151     connect(m_ui->m_zoomOutAct, &QAction::triggered, this, [this]() { m_pdfCtrl->zoomOut(); });
0152 
0153     m_ui->m_continuousAct->setChecked(true);
0154     m_ui->m_view->setPageMode(QPdfView::PageMode::MultiPage);
0155 
0156     connect(m_pdfCtrl, &PdfController::zoomFactorChanged, m_ui->m_view, &QPdfView::setZoomFactor);
0157 
0158     connect(m_ui->bookmarkView, &QTreeView::activated, this, &PdfViewer::bookmarkSelected);
0159 
0160     auto nav= m_ui->m_view->pageNavigator();
0161     auto updateCurrentPage= [this, nav]()
0162     {
0163         if(!nav)
0164             return;
0165 
0166         m_ui->m_curentPage->setValue(nav->currentPage() + 1); //.arg(m_document->pageCount()));
0167     };
0168 
0169     auto updatePageCount= [this]()
0170     {
0171         m_ui->m_curentPage->setMinimum(1);
0172         m_ui->m_curentPage->setMaximum(m_document->pageCount());
0173         m_ui->m_pageCount->setText(QString("/ %1").arg(m_document->pageCount()));
0174     };
0175 
0176     connect(nav, &QPdfPageNavigator::currentPageChanged, this, updateCurrentPage);
0177     connect(m_document.get(), &QPdfDocument::pageCountChanged, this, updatePageCount);
0178     connect(nav, &QPdfPageNavigator::forwardAvailableChanged, m_ui->m_nextPageAct, &QAction::setEnabled);
0179     connect(nav, &QPdfPageNavigator::backAvailableChanged, m_ui->m_previousPageAct, &QAction::setEnabled);
0180 
0181     m_ui->m_nextPageAct->setEnabled(nav->forwardAvailable());
0182     m_ui->m_previousPageAct->setEnabled(nav->backAvailable());
0183 
0184     updateCurrentPage();
0185     updatePageCount();
0186 
0187     connect(m_ui->m_nextPageAct, &QAction::triggered, nav, &QPdfPageNavigator::forward);
0188     connect(m_ui->m_previousPageAct, &QAction::triggered, nav, &QPdfPageNavigator::back);
0189     connect(m_ui->m_curentPage, &QSpinBox::valueChanged, this,
0190             [this, nav]() {
0191                 nav->update(m_ui->m_curentPage->value() - 1, QPointF{0, 0}, nav->currentZoom());
0192             });
0193 
0194     m_ui->m_view->installEventFilter(this);
0195 
0196     connect(m_ui->m_exportToImage, &QAction::triggered, this, &PdfViewer::extractImage);
0197     connect(m_ui->m_exportToMapAct, &QAction::triggered, this, &PdfViewer::extractMap);
0198     connect(m_ui->m_extractTextAct, &QAction::triggered, this, &PdfViewer::extractText);
0199 
0200     connect(m_ui->m_cropViewAct, &QAction::triggered, this,
0201             [this]()
0202             {
0203                 m_ui->m_exportToImage->setEnabled(m_ui->m_cropViewAct->isChecked());
0204                 m_ui->m_exportToMapAct->setEnabled(m_ui->m_cropViewAct->isChecked());
0205                 m_ui->m_extractTextAct->setEnabled(m_ui->m_cropViewAct->isChecked());
0206             });
0207     connect(m_ui->m_cropViewAct, &QAction::triggered, this, &PdfViewer::showOverLay);
0208 }
0209 
0210 bool PdfViewer::eventFilter(QObject* obj, QEvent* event)
0211 {
0212     if(event->type() == QEvent::Resize && m_overlay && obj == m_ui->m_view)
0213     {
0214         auto geo= m_ui->m_view->geometry();
0215         m_overlay->setGeometry({m_ui->m_view->mapFromParent(geo.topLeft()), geo.size()});
0216         return QObject::eventFilter(obj, event);
0217     }
0218     else
0219     {
0220         return QObject::eventFilter(obj, event);
0221     }
0222 }
0223 
0224 void PdfViewer::extractImage()
0225 {
0226     if(!m_overlay)
0227         return;
0228 
0229     auto rect= m_overlay->selectedRect();
0230     auto pix= m_ui->m_view->grab(rect);
0231     // m_pdfCtrl->shareImageIntoImage(pix);
0232     m_overlay.reset();
0233 }
0234 
0235 void PdfViewer::extractMap()
0236 {
0237     if(!m_overlay)
0238         return;
0239     auto rect= m_overlay->selectedRect();
0240     m_ui->m_cropViewAct->setChecked(false);
0241     m_overlay.reset(nullptr);
0242     m_pdfCtrl->copyImage(m_ui->m_view->grab(rect));
0243     m_ui->m_exportToMapAct->setEnabled(false);
0244 }
0245 void PdfViewer::extractText()
0246 {
0247     if(!m_overlay)
0248         return;
0249     /*auto rect= m_overlay->selectedRect();
0250     auto geo= m_ui->m_view->geometry();
0251     auto margins= m_ui->m_view->documentMargins();
0252     auto nav= m_ui->m_view->pageNavigator();
0253     auto pos= nav->currentLocation();
0254     auto page= nav->currentPage();
0255     auto zoomLevel= m_ui->m_view->zoomFactor();
0256     // auto pix= m_ui->m_view->select(rect);
0257     // m_pdfCtrl->shareImageIntoMap(pix);
0258 
0259     auto geoPage= geo.marginsRemoved(margins);
0260 
0261     auto rectPage= rect.marginsRemoved(QMargins{margins.left(), margins.top(), 0, 0});
0262     qCWarning(MediaContainerPDF) << "Geo:" << geo << "rect:" << rect << "margins:" << margins << "GeoPage:" << geoPage
0263                                  << "rectpage" << rectPage << "zoom" << zoomLevel;
0264 
0265 
0266 
0267     // qCWarning(MediaContainerPDF) << geoPage << rect << ;
0268     //  geo
0269 
0270     auto selections= m_document->getSelection(page, rectPage.toRectF().topLeft(), rectPage.toRectF().bottomRight());
0271     qCWarning(MediaContainerPDF) << selections.text();
0272 
0273     QRectF rectZoom(rect.x() * zoomLevel, rect.y() * zoomLevel, rect.width() * zoomLevel, rect.height() * zoomLevel);
0274     auto selections2= m_document->getSelection(page, rectZoom.topLeft(), rectZoom.bottomRight());
0275     qCWarning(MediaContainerPDF) << selections2.text();
0276     // m_overlay.reset();*/
0277 }
0278 
0279 void PdfViewer::sharePdfTo()
0280 {
0281     auto answer
0282         = QMessageBox::question(this, tr("Sharing Pdf File"),
0283                                 tr("PDF transfer can be really heavy.\nDo you want to continue and share the PDF?"),
0284                                 QMessageBox::Yes | QMessageBox::Cancel);
0285     if(answer == QMessageBox::Yes)
0286     {
0287         m_pdfCtrl->shareAsPdf();
0288     }
0289 }
0290 
0291 void PdfViewer::updateTitle()
0292 {
0293     setWindowTitle(tr("%1 - (PDF)").arg(m_pdfCtrl->name()));
0294 }
0295 
0296 void PdfViewer::bookmarkSelected(const QModelIndex& index)
0297 {
0298     if(!index.isValid())
0299         return;
0300 
0301     const int page= index.data(qToUnderlying<QPdfBookmarkModel::Role>(QPdfBookmarkModel::Role::Page)).toInt();
0302     m_ui->m_view->pageNavigator()->jump(page, {10, 10});
0303 }
0304 
0305 void PdfViewer::showOverLay()
0306 {
0307     if(m_ui->m_cropViewAct->isChecked())
0308     {
0309 
0310         if(!m_overlay)
0311         {
0312             m_overlay.reset(new Overlay(m_ui->m_view));
0313         }
0314         auto geo= m_ui->m_view->geometry();
0315         m_overlay->setGeometry({m_ui->m_view->mapFromParent(geo.topLeft()), geo.size()});
0316         m_overlay->show();
0317     }
0318     else
0319     {
0320         if(m_overlay != nullptr)
0321         {
0322             m_overlay->hide();
0323             m_overlay.reset(nullptr);
0324             m_ui->m_exportToMapAct->setEnabled(false);
0325         }
0326     }
0327 }
0328 
0329 void PdfViewer::savePdfToFile(QDataStream& out)
0330 {
0331     Q_UNUSED(out)
0332     //    QByteArray baPdfViewer;
0333     //    QBuffer bufPdfViewer(&baPdfViewer);
0334     //    if(!m_pixMap.isNull())
0335     //    {
0336     //        if (!m_pixMap.save(&bufPdfViewer, "jpg", 70))
0337     //        {
0338     //            error(tr("PdfViewer Compression fails (savePdfViewerToFile - PdfViewer.cpp)"),this);
0339     //            return;
0340     //        }
0341     //        out << baPdfViewer;
0342     //    }
0343 }
0344 
0345 void PdfViewer::contextMenuEvent(QContextMenuEvent* event)
0346 {
0347     QMenu menu(this);
0348 
0349     menu.addAction(m_ui->m_cropViewAct);
0350     menu.addAction(m_ui->m_exportToMapAct);
0351     menu.addAction(m_ui->m_continuousAct);
0352     menu.addSeparator();
0353     menu.addAction(m_ui->m_zoomInAct);
0354     menu.addAction(m_ui->m_zoomOutAct);
0355     menu.addSeparator();
0356     menu.addAction(m_ui->m_shareAct);
0357 
0358     menu.exec(event->globalPos());
0359 }
0360 
0361 /*void PdfViewer::putDataIntoCleverUri()
0362 {
0363    QByteArray data;
0364    QDataStream out(&data, QIODevice::WriteOnly);
0365    savePdfToFile(out);
0366    if(nullptr != m_uri)
0367    {
0368        m_uri->setData(data);
0369    }
0370 }*/