mirror of
				https://github.com/JakubMelka/PDF4QT.git
				synced 2025-06-05 21:59:17 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			175 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			175 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //    Copyright (C) 2020-2021 Jakub Melka
 | |
| //
 | |
| //    This file is part of Pdf4Qt.
 | |
| //
 | |
| //    Pdf4Qt is free software: you can redistribute it and/or modify
 | |
| //    it under the terms of the GNU Lesser General Public License as published by
 | |
| //    the Free Software Foundation, either version 3 of the License, or
 | |
| //    with the written consent of the copyright owner, any later version.
 | |
| //
 | |
| //    Pdf4Qt is distributed in the hope that it will be useful,
 | |
| //    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | |
| //    GNU Lesser General Public License for more details.
 | |
| //
 | |
| //    You should have received a copy of the GNU Lesser General Public License
 | |
| //    along with Pdf4Qt.  If not, see <https://www.gnu.org/licenses/>.
 | |
| 
 | |
| #include "pdfpagenavigation.h"
 | |
| 
 | |
| namespace pdf
 | |
| {
 | |
| 
 | |
| PDFPageNavigation::PDFPageNavigation(const PDFDocument* document, QObject* parent) :
 | |
|     QObject(parent),
 | |
|     m_currentPageIndex(0),
 | |
|     m_document(document)
 | |
| {
 | |
|     if (m_document && m_document->getCatalog()->getPageCount() > 0)
 | |
|     {
 | |
|         navigateToPage(0);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void PDFPageNavigation::navigateToPage(size_t pageIndex)
 | |
| {
 | |
|     if (m_currentPageIndex == pageIndex)
 | |
|     {
 | |
|         // Jakub Melka: We are at the same page! Do nothing.
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     const bool isForward = pageIndex > m_currentPageIndex;
 | |
|     const PDFObjectStorage* const storage = &m_document->getStorage();
 | |
|     const PDFPage* page = m_document->getCatalog()->getPage(pageIndex);
 | |
| 
 | |
|     // We will perform steps as in PDF 2.0 specification, chapter 12.4.4.2
 | |
|     // Step a) navigate to page and set current navigation node
 | |
|     m_currentPageIndex = pageIndex;
 | |
|     m_transition = PDFPageTransition::parse(storage, page->getTransition(storage));
 | |
|     m_currentNavigationNode = PDFNavigationNode::parse(storage, page->getFirstSubpageNavigationNode(storage));
 | |
| 
 | |
|     // Step b) Execute initially page navigation node. If we are navigating forward,
 | |
|     //         then "next" action should be executed and current node should be changed to next.
 | |
|     //         If we are navigating backward, then "previous" action should be executed
 | |
|     //         and current node should be changed to previous.
 | |
|     executeNavigationNode(isForward ? Direction::Forward : Direction::Backward);
 | |
| 
 | |
|     // Step c) Navigate to new page - send navigation request.
 | |
|     emit pageChangeRequest(m_currentPageIndex, &m_transition);
 | |
| }
 | |
| 
 | |
| void PDFPageNavigation::navigateForward()
 | |
| {
 | |
|     if (m_currentNavigationNode)
 | |
|     {
 | |
|         executeNavigationNode(Direction::Forward);
 | |
|     }
 | |
|     else if (m_currentPageIndex + 1 < m_document->getCatalog()->getPageCount())
 | |
|     {
 | |
|         navigateToPage(m_currentPageIndex + 1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void PDFPageNavigation::navigateBackward()
 | |
| {
 | |
|     if (m_currentNavigationNode)
 | |
|     {
 | |
|         executeNavigationNode(Direction::Backward);
 | |
|     }
 | |
|     else if (m_currentPageIndex > 0)
 | |
|     {
 | |
|         navigateToPage(m_currentPageIndex - 1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void PDFPageNavigation::executeNavigationNode(Direction direction)
 | |
| {
 | |
|     if (!m_currentNavigationNode)
 | |
|     {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     // We will make a copy of object, because this object can change,
 | |
|     // when actions are executed.
 | |
|     PDFNavigationNode copy = *m_currentNavigationNode;
 | |
|     m_currentNavigationNode = PDFNavigationNode::parse(&m_document->getStorage(), m_document->getObjectByReference((direction == Direction::Forward) ? copy.getNextNode() : copy.getPreviousNode()));
 | |
| 
 | |
|     switch (direction)
 | |
|     {
 | |
|         case Direction::Forward:
 | |
|         {
 | |
|             if (const PDFAction* action = copy.getNextAction().get())
 | |
|             {
 | |
|                 for (const PDFAction* currentAction : action->getActionList())
 | |
|                 {
 | |
|                     emit actionTriggered(currentAction);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         case Direction::Backward:
 | |
|         {
 | |
|             if (const PDFAction* action = copy.getPreviousAction().get())
 | |
|             {
 | |
|                 for (const PDFAction* currentAction : action->getActionList())
 | |
|                 {
 | |
|                     emit actionTriggered(currentAction);
 | |
|                 }
 | |
|             }
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         default:
 | |
|             Q_ASSERT(false);
 | |
|             break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| PDFActionPtr PDFNavigationNode::getPreviousAction() const
 | |
| {
 | |
|     return m_previousAction;
 | |
| }
 | |
| 
 | |
| PDFActionPtr PDFNavigationNode::getNextAction() const
 | |
| {
 | |
|     return m_nextAction;
 | |
| }
 | |
| 
 | |
| PDFObjectReference PDFNavigationNode::getPreviousNode() const
 | |
| {
 | |
|     return m_previousNode;
 | |
| }
 | |
| 
 | |
| PDFObjectReference PDFNavigationNode::getNextNode() const
 | |
| {
 | |
|     return m_nextNode;
 | |
| }
 | |
| 
 | |
| PDFReal PDFNavigationNode::getDuration() const
 | |
| {
 | |
|     return m_duration;
 | |
| }
 | |
| 
 | |
| std::optional<PDFNavigationNode> PDFNavigationNode::parse(const PDFObjectStorage* storage, PDFObject object)
 | |
| {
 | |
|     std::optional<PDFNavigationNode> result;
 | |
| 
 | |
|     if (const PDFDictionary* dictionary = storage->getDictionaryFromObject(object))
 | |
|     {
 | |
|         PDFDocumentDataLoaderDecorator loader(storage);
 | |
| 
 | |
|         result = PDFNavigationNode();
 | |
|         result->m_nextAction = PDFAction::parse(storage, dictionary->get("NA"));
 | |
|         result->m_previousAction = PDFAction::parse(storage, dictionary->get("PA"));
 | |
|         result->m_previousNode = loader.readReferenceFromDictionary(dictionary, "Prev");
 | |
|         result->m_nextNode = loader.readReferenceFromDictionary(dictionary, "Next");
 | |
|         result->m_duration = loader.readNumberFromDictionary(dictionary, "Dur", 0.0);
 | |
|     }
 | |
| 
 | |
|     return result;
 | |
| }
 | |
| 
 | |
| }   // namespace pdf
 |