mirror of
https://invent.kde.org/graphics/okular
synced 2024-11-05 18:34:53 +00:00
34b8e28322
- Page: rotation does not switch height and width - Document/Part/Generator: 1. Add API for attaching stuff to the interface: ActionCollection and the Navigation Panel also add possibility to merge an XML .rc file with menu layout. Relevant functions are: QString Generator::getXMLFile(), returns a QString with your .rc file name. void Generator::setupGUI (KActionCollection* , QToolbox* ), add your components to the user interface 2. Supporting backend settings: If during startup, backends which provide a configuration ([X-KDE-oKularHasInternalSettings] set to true) are found, a menu item: configure backends is created, clicking on it results in loading all the generators that have settings, but not those that dont. the Generator::addPages(KConfigDialog *dlg) function should be overloaded by a generator and dlg->addPage should be used to add pages. If a user opens a file that needs an already loaded generator, the already loaded one is used instead of loading another. 3. Error/Warning/Notice sending support, to send a notice/error/warning, add a relevant notice/error/warning(QString& txt ,int duration) to the generator class, and sending a message to the user is as simple as emitting a signal! 4. Intercepting of events generated by the PageView is done by Generator::handleEvent(QEvent*), subclass it, do a switch on QEvent::type(), handle your event and return true if pageview is to proceed with its handling or false if not. 5. Support configuring the KPrinter on the generator side, use Generator::canConfigurePrinter(), return true there, and you get a nonconfigured KPrinter in your Generator::print() 6. PixmapRequest handling update: a.) Generator::canGeneratePixmap is now Generator::canGeneratePixmap(bool async) b.) Document::sendGeneratorRequests is a slot now c.) Old way of sending pixmaps (Document::requestPixmaps(QValueList<PixmapRequest*> checking if we can generate pixmap if not, waiting for receiving) is replaced with: requestPixmaps only queues the pixmap all checking if w can generate is done in sendGeneratorReqest, the sendGeneratorRequest is run in three places: 1. in requestPixmaps when we receive a request 2. in requestDone if pixmapStack is not empty 3. sendGeneratorRequest, apart from removing invalid requests, takes the current request and if generator canGeratePixmap(request->async) it removes the pixmap from stack and sends to generator if not, QTimer::singleshots to itself after 20ms, it ends when stack has no valid pixmap request 7. Added a commented out zoom field to PixmapGenerator, mightcome in handy sometime - TextPage: add instructions that handle simplyfing the RegularAreaRect, no more double painted borders in selection rectangles, this rocks. svn path=/trunk/playground/graphics/oKular/kpdf/; revision=445196
384 lines
11 KiB
C++
384 lines
11 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2004 by Enrico Ros <eros.kde@email.it> *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
* (at your option) any later version. *
|
|
***************************************************************************/
|
|
|
|
// qt/kde includes
|
|
#include <qpixmap.h>
|
|
#include <qstring.h>
|
|
#include <qmap.h>
|
|
#include <qdom.h>
|
|
#include <kdebug.h>
|
|
|
|
// local includes
|
|
#include "page.h"
|
|
#include "pagetransition.h"
|
|
#include "link.h"
|
|
#include "annotations.h"
|
|
#include "conf/settings.h"
|
|
#include "area.h"
|
|
//include "xpdf/TextOutputDev.h"
|
|
|
|
// temp includes
|
|
#include <sys/time.h>
|
|
|
|
|
|
/** class KPDFPage **/
|
|
|
|
KPDFPage::KPDFPage( uint page, double w, double h, int r )
|
|
: m_number( page ), m_rotation( r ), m_width( w ), m_height( h ),
|
|
m_bookmarked( false ), m_text( 0 ), m_transition( 0 )
|
|
{
|
|
// if landscape swap width <-> height (rotate 90deg CCW)
|
|
/* if ( r == 90 || r == 270 )
|
|
{
|
|
m_width = h;
|
|
m_height = w;
|
|
}*/
|
|
// avoid Division-By-Zero problems in the program
|
|
if ( m_width <= 0 )
|
|
m_width = 1;
|
|
if ( m_height <= 0 )
|
|
m_height = 1;
|
|
}
|
|
|
|
KPDFPage::~KPDFPage()
|
|
{
|
|
deletePixmapsAndRects();
|
|
deleteHighlights();
|
|
deleteAnnotations();
|
|
delete m_text;
|
|
delete m_transition;
|
|
}
|
|
|
|
|
|
bool KPDFPage::hasPixmap( int id, int width, int height ) const
|
|
{
|
|
if ( !m_pixmaps.contains( id ) )
|
|
return false;
|
|
if ( width == -1 || height == -1 )
|
|
return true;
|
|
QPixmap * p = m_pixmaps[ id ];
|
|
return p ? ( p->width() == width && p->height() == height ) : false;
|
|
}
|
|
|
|
bool KPDFPage::hasSearchPage() const
|
|
{
|
|
return m_text != 0;
|
|
}
|
|
|
|
bool KPDFPage::hasBookmark() const
|
|
{
|
|
return m_bookmarked;
|
|
}
|
|
|
|
bool KPDFPage::hasObjectRect( double x, double y ) const
|
|
{
|
|
if ( m_rects.count() < 1 )
|
|
return false;
|
|
QValueList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end();
|
|
for ( ; it != end; ++it )
|
|
if ( (*it)->contains( x, y ) )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool KPDFPage::hasHighlights( int s_id ) const
|
|
{
|
|
// simple case: have no highlights
|
|
if ( m_highlights.isEmpty() )
|
|
return false;
|
|
// simple case: we have highlights and no id to match
|
|
if ( s_id == -1 )
|
|
return true;
|
|
// iterate on the highlights list to find an entry by id
|
|
QValueList< HighlightAreaRect * >::const_iterator it = m_highlights.begin(), end = m_highlights.end();
|
|
for ( ; it != end; ++it )
|
|
if ( (*it)->s_id == s_id )
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
bool KPDFPage::hasTransition() const
|
|
{
|
|
return m_transition != 0;
|
|
}
|
|
|
|
|
|
RegularAreaRect * KPDFPage::findText( const QString & text, SearchDir dir, const bool strictCase,
|
|
const RegularAreaRect * lastRect/*, const Generator &generator */) const
|
|
{
|
|
RegularAreaRect* ret=0;
|
|
if ( text.isEmpty() )
|
|
return ret;
|
|
/*
|
|
if (generator->preferInternalSearch())
|
|
return generator->;*/
|
|
|
|
ret=m_text->findText(text, dir, strictCase,lastRect);
|
|
return ret;
|
|
/*
|
|
|
|
*/
|
|
}
|
|
|
|
QString * KPDFPage::getText( const RegularAreaRect * area ) const
|
|
{
|
|
QString *ret= 0;
|
|
|
|
if ( !m_text )
|
|
return ret;
|
|
|
|
ret = m_text->getText( area );
|
|
|
|
return ret;
|
|
}
|
|
|
|
const ObjectRect * KPDFPage::getObjectRect( ObjectRect::ObjectType type, double x, double y ) const
|
|
{
|
|
QValueList< ObjectRect * >::const_iterator it = m_rects.begin(), end = m_rects.end();
|
|
for ( ; it != end; ++it )
|
|
if ( (*it)->contains( x, y ) && ((*it)->objectType() == type) )
|
|
return *it;
|
|
return 0;
|
|
}
|
|
|
|
const KPDFPageTransition * KPDFPage::getTransition() const
|
|
{
|
|
return m_transition;
|
|
}
|
|
|
|
|
|
void KPDFPage::setPixmap( int id, QPixmap * pixmap )
|
|
{
|
|
if ( m_pixmaps.contains( id ) )
|
|
delete m_pixmaps[id];
|
|
m_pixmaps[id] = pixmap;
|
|
}
|
|
|
|
void KPDFPage::setSearchPage( KPDFTextPage * tp )
|
|
{
|
|
delete m_text;
|
|
m_text = tp;
|
|
}
|
|
|
|
void KPDFPage::setBookmark( bool state )
|
|
{
|
|
m_bookmarked = state;
|
|
}
|
|
|
|
void KPDFPage::setObjectRects( const QValueList< ObjectRect * > rects )
|
|
{
|
|
QValueList< ObjectRect * >::iterator it = m_rects.begin(), end = m_rects.end();
|
|
for ( ; it != end; ++it )
|
|
delete *it;
|
|
m_rects = rects;
|
|
}
|
|
|
|
/*
|
|
void KPDFPage::setHighlight( int s_id, const QColor & color )
|
|
{
|
|
QValueList<HighlightAreaRect*>::Iterator it=m_highlights.begin();
|
|
HighlightAreaRect* tmp;
|
|
while(it!=m_highlights.end())
|
|
{
|
|
tmp = *(it);
|
|
if (tmp->s_id == s_id)
|
|
tmp->color=color;
|
|
++it;
|
|
}
|
|
}*/
|
|
|
|
//
|
|
void KPDFPage::setHighlight( int s_id, RegularAreaRect *rect, const QColor & color )
|
|
{
|
|
HighlightAreaRect * hr = new HighlightAreaRect(rect);
|
|
hr->s_id = s_id;
|
|
hr->color = color;
|
|
m_highlights.append( hr );
|
|
|
|
/* for (i=static_cast<RegularAreaRect::Iterator>(rect.begin());i!=rect.end();i++)
|
|
{
|
|
// create a HighlightRect descriptor taking values from params
|
|
NormalizedRect *t = new NormalizedRect;
|
|
t->left = i->left;
|
|
t->top = i->top;
|
|
t->right = i->right;
|
|
t->bottom = i->bottom;
|
|
// append the HighlightRect to the list
|
|
hr->append( t );
|
|
// delete old object and change reference (whyyy?)
|
|
delete rect;
|
|
rect = hr;
|
|
}*/
|
|
}
|
|
|
|
|
|
void KPDFPage::addAnnotation( Annotation * annotation )
|
|
{
|
|
m_annotations.append( annotation );
|
|
}
|
|
|
|
void KPDFPage::setTransition( KPDFPageTransition * transition )
|
|
{
|
|
delete m_transition;
|
|
m_transition = transition;
|
|
}
|
|
|
|
void KPDFPage::deletePixmap( int id )
|
|
{
|
|
if ( m_pixmaps.contains( id ) )
|
|
{
|
|
delete m_pixmaps[ id ];
|
|
m_pixmaps.remove( id );
|
|
}
|
|
}
|
|
|
|
void KPDFPage::deletePixmapsAndRects()
|
|
{
|
|
// delete all stored pixmaps
|
|
QMap<int,QPixmap *>::iterator it = m_pixmaps.begin(), end = m_pixmaps.end();
|
|
for ( ; it != end; ++it )
|
|
delete *it;
|
|
m_pixmaps.clear();
|
|
// delete ObjectRects
|
|
QValueList< ObjectRect * >::iterator rIt = m_rects.begin(), rEnd = m_rects.end();
|
|
for ( ; rIt != rEnd; ++rIt )
|
|
delete *rIt;
|
|
m_rects.clear();
|
|
}
|
|
|
|
void KPDFPage::deleteHighlights( int s_id )
|
|
{
|
|
// delete highlights by ID
|
|
QValueList< HighlightAreaRect* >::iterator it = m_highlights.begin(), end = m_highlights.end();
|
|
while ( it != end )
|
|
{
|
|
HighlightAreaRect* highlight = *it;
|
|
if ( s_id == -1 || highlight->s_id == s_id )
|
|
{
|
|
it = m_highlights.remove( it );
|
|
delete highlight;
|
|
}
|
|
else
|
|
++it;
|
|
}
|
|
}
|
|
|
|
void KPDFPage::deleteAnnotations()
|
|
{
|
|
// delete all stored annotations
|
|
QValueList< Annotation * >::iterator aIt = m_annotations.begin(), aEnd = m_annotations.end();
|
|
for ( ; aIt != aEnd; ++aIt )
|
|
delete *aIt;
|
|
m_annotations.clear();
|
|
}
|
|
|
|
void KPDFPage::restoreLocalContents( const QDomNode & pageNode )
|
|
{
|
|
// iterate over all chilren (bookmark, annotationList, ...)
|
|
QDomNode childNode = pageNode.firstChild();
|
|
while ( childNode.isElement() )
|
|
{
|
|
QDomElement childElement = childNode.toElement();
|
|
childNode = childNode.nextSibling();
|
|
|
|
// parse annotationList child element
|
|
if ( childElement.tagName() == "annotationList" )
|
|
{
|
|
struct timeval ts, te;
|
|
gettimeofday( &ts, NULL );
|
|
// iterate over all annotations
|
|
QDomNode annotationNode = childElement.firstChild();
|
|
while( annotationNode.isElement() )
|
|
{
|
|
// get annotation element and advance to next annot
|
|
QDomElement annotElement = annotationNode.toElement();
|
|
annotationNode = annotationNode.nextSibling();
|
|
|
|
// get annotation from the dom element
|
|
Annotation * annotation = AnnotationUtils::createAnnotation( annotElement );
|
|
|
|
// append annotation to the list or show warning
|
|
if ( annotation )
|
|
m_annotations.append( annotation );
|
|
else
|
|
kdWarning() << "page (" << m_number << "): can't restore an annotation from XML." << endl;
|
|
}
|
|
gettimeofday( &te, NULL );
|
|
double startTime = (double)ts.tv_sec + ((double)ts.tv_usec) / 1000000.0;
|
|
double endTime = (double)te.tv_sec + ((double)te.tv_usec) / 1000000.0;
|
|
kdDebug() << "annots: XML Load time: " << (endTime-startTime)*1000.0 << "ms" << endl;
|
|
}
|
|
|
|
// parse bookmark child element
|
|
else if ( childElement.tagName() == "bookmark" )
|
|
m_bookmarked = true;
|
|
}
|
|
}
|
|
|
|
void KPDFPage::saveLocalContents( QDomNode & parentNode, QDomDocument & document )
|
|
{
|
|
// only add a node if there is some stuff to write into
|
|
if ( !m_bookmarked && m_annotations.isEmpty() )
|
|
return;
|
|
|
|
// create the page node and set the 'number' attribute
|
|
QDomElement pageElement = document.createElement( "page" );
|
|
pageElement.setAttribute( "number", m_number );
|
|
|
|
// add bookmark info if is bookmarked
|
|
if ( m_bookmarked )
|
|
{
|
|
// create the pageElement's 'bookmark' child
|
|
QDomElement bookmarkElement = document.createElement( "bookmark" );
|
|
pageElement.appendChild( bookmarkElement );
|
|
|
|
// add attributes to the element
|
|
//bookmarkElement.setAttribute( "name", bookmark name );
|
|
}
|
|
|
|
// add annotations info if has got any
|
|
if ( !m_annotations.isEmpty() )
|
|
{
|
|
#if 0
|
|
struct timeval ts, te;
|
|
gettimeofday( &ts, NULL );
|
|
#endif
|
|
// create the annotationList
|
|
QDomElement annotListElement = document.createElement( "annotationList" );
|
|
|
|
// add every annotation to the annotationList
|
|
QValueList< Annotation * >::iterator aIt = m_annotations.begin(), aEnd = m_annotations.end();
|
|
for ( ; aIt != aEnd; ++aIt )
|
|
{
|
|
// get annotation
|
|
const Annotation * a = *aIt;
|
|
// only save kpdf annotations (not the embedded in file ones)
|
|
if ( !(a->flags & Annotation::External) )
|
|
{
|
|
// append an filled-up element called 'annotation' to the list
|
|
QDomElement annElement = document.createElement( "annotation" );
|
|
AnnotationUtils::storeAnnotation( a, annElement, document );
|
|
annotListElement.appendChild( annElement );
|
|
}
|
|
}
|
|
|
|
// append the annotationList element if annotations have been set
|
|
if ( annotListElement.hasChildNodes() )
|
|
pageElement.appendChild( annotListElement );
|
|
#if 0
|
|
gettimeofday( &te, NULL );
|
|
double startTime = (double)ts.tv_sec + ((double)ts.tv_usec) / 1000000.0;
|
|
double endTime = (double)te.tv_sec + ((double)te.tv_usec) / 1000000.0;
|
|
kdDebug() << "annots: XML Save Time: " << (endTime-startTime)*1000.0 << "ms" << endl;
|
|
#endif
|
|
}
|
|
|
|
// append the page element only if has children
|
|
if ( pageElement.hasChildNodes() )
|
|
parentNode.appendChild( pageElement );
|
|
}
|