mirror of
https://invent.kde.org/graphics/okular
synced 2024-08-25 02:45:38 +00:00
Merge branch 'master' into mart/okularActive
This commit is contained in:
commit
d11d5d8106
|
@ -101,6 +101,7 @@ install( FILES
|
|||
interfaces/configinterface.h
|
||||
interfaces/guiinterface.h
|
||||
interfaces/printinterface.h
|
||||
interfaces/saveinterface.h
|
||||
interfaces/viewerinterface.h
|
||||
DESTINATION ${INCLUDE_INSTALL_DIR}/okular/interfaces COMPONENT Devel)
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
// local includes
|
||||
#include "document.h"
|
||||
#include "document_p.h"
|
||||
#include "movie.h"
|
||||
#include "page_p.h"
|
||||
#include "sound.h"
|
||||
|
@ -100,6 +101,9 @@ QRect AnnotationUtils::annotationGeometry( const Annotation * ann,
|
|||
}
|
||||
//END AnnotationUtils implementation
|
||||
|
||||
AnnotationProxy::~AnnotationProxy()
|
||||
{
|
||||
}
|
||||
|
||||
//BEGIN Annotation implementation
|
||||
|
||||
|
@ -732,9 +736,9 @@ void Annotation::setDisposeDataFunction( DisposeDataFunction func )
|
|||
bool Annotation::canBeMoved() const
|
||||
{
|
||||
Q_D( const Annotation );
|
||||
// for now, it is pointless moving external annotations
|
||||
// as we cannot change them anyway
|
||||
if ( d->m_flags & External )
|
||||
|
||||
// Don't move annotations if they cannot be modified
|
||||
if ( !d->m_page || !d->m_page->m_doc->m_parent->canModifyPageAnnotation(this) )
|
||||
return false;
|
||||
|
||||
// highlight "requires" to be "bounded" to text, and that's tricky for now
|
||||
|
@ -764,8 +768,8 @@ void Annotation::store( QDomNode & annNode, QDomDocument & document ) const
|
|||
e.setAttribute( "creationDate", d->m_creationDate.toString(Qt::ISODate) );
|
||||
|
||||
// store -other- attributes
|
||||
if ( d->m_flags )
|
||||
e.setAttribute( "flags", d->m_flags );
|
||||
if ( d->m_flags ) // Strip internal flags
|
||||
e.setAttribute( "flags", d->m_flags & ~(External | ExternallyDrawn | BeingMoved) );
|
||||
if ( d->m_style.color().isValid() )
|
||||
e.setAttribute( "color", d->m_style.color().name() );
|
||||
if ( d->m_style.opacity() != 1.0 )
|
||||
|
|
|
@ -128,7 +128,8 @@ class OKULAR_EXPORT Annotation
|
|||
DenyDelete = 32, ///< Cannot be deleted
|
||||
ToggleHidingOnMouse = 64, ///< Can be hidden/shown by mouse click
|
||||
External = 128, ///< Is stored external
|
||||
ExternallyDrawn = 256 ///< Is drawn externally (eg the generator which povided it) @since 0.10 (KDE 4.4)
|
||||
ExternallyDrawn = 256, ///< Is drawn externally (by the generator which provided it) @since 0.10 (KDE 4.4)
|
||||
BeingMoved = 512 ///< Is being moved (mouse drag and drop). If ExternallyDrawn, the generator must not draw it @since 0.15 (KDE 4.9)
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -655,6 +656,59 @@ class OKULAR_EXPORT Annotation
|
|||
Q_DISABLE_COPY( Annotation )
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Native annotation interface
|
||||
*
|
||||
* Generators can subclass it to provide native annotation support.
|
||||
* Generators can use Annotation::setNativeId to store per-annotation data.
|
||||
*
|
||||
* @since 0.15 (KDE 4.9)
|
||||
*/
|
||||
class OKULAR_EXPORT AnnotationProxy
|
||||
{
|
||||
public:
|
||||
enum Capability
|
||||
{
|
||||
Addition, ///< Generator can create native annotations
|
||||
Modification, ///< Generator can edit native annotations
|
||||
Removal ///< Generator can remove native annotations
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroys the annotation proxy.
|
||||
*/
|
||||
virtual ~AnnotationProxy();
|
||||
|
||||
/**
|
||||
* Query for the supported capabilities.
|
||||
*/
|
||||
virtual bool supports( Capability capability ) const = 0;
|
||||
|
||||
/**
|
||||
* Called when a new @p annotation is added to a @p page.
|
||||
*
|
||||
* @note Only called if supports(Addition) == true
|
||||
*/
|
||||
virtual void notifyAddition( Annotation *annotation, int page ) = 0;
|
||||
|
||||
/**
|
||||
* Called after an existing @p annotation at a given @p page is modified.
|
||||
*
|
||||
* Generator can call @p annotation getters to get the new values.
|
||||
* @p appearanceChanged tells if a non-visible property was modifed
|
||||
*
|
||||
* @note Only called if supports(Modification) == true
|
||||
*/
|
||||
virtual void notifyModification( const Annotation *annotation, int page, bool appearanceChanged ) = 0;
|
||||
|
||||
/**
|
||||
* Called when an existing @p annotation at a given @p page is removed.
|
||||
*
|
||||
* @note Only called if supports(Removal) == true
|
||||
*/
|
||||
virtual void notifyRemoval( Annotation *annotation, int page ) = 0;
|
||||
};
|
||||
|
||||
class OKULAR_EXPORT TextAnnotation : public Annotation
|
||||
{
|
||||
public:
|
||||
|
|
|
@ -771,6 +771,24 @@ DocumentViewport DocumentPrivate::nextDocumentViewport() const
|
|||
return ret;
|
||||
}
|
||||
|
||||
void DocumentPrivate::warnLimitedAnnotSupport()
|
||||
{
|
||||
if ( !m_showWarningLimitedAnnotSupport )
|
||||
return;
|
||||
m_showWarningLimitedAnnotSupport = false; // Show the warning once
|
||||
|
||||
if ( canAddAnnotationsNatively() )
|
||||
{
|
||||
// Show only if there are external annotations (we follow the usual XML path otherwise)
|
||||
if ( m_containsExternalAnnotations )
|
||||
KMessageBox::sorry( m_parent->widget(), i18n("Your changes will not be saved automatically. Use File -> Save As... or your changes will be lost") );
|
||||
}
|
||||
else
|
||||
{
|
||||
KMessageBox::information( m_parent->widget(), i18n("You can save the annotated document using File -> Export As -> Document Archive"), QString(), "annotExportAsArchive" );
|
||||
}
|
||||
}
|
||||
|
||||
void DocumentPrivate::saveDocumentInfo() const
|
||||
{
|
||||
if ( m_xmlFileName.isEmpty() )
|
||||
|
@ -791,10 +809,13 @@ void DocumentPrivate::saveDocumentInfo() const
|
|||
// 2.1. Save page attributes (bookmark state, annotations, ... ) to DOM
|
||||
QDomElement pageList = doc.createElement( "pageList" );
|
||||
root.appendChild( pageList );
|
||||
PageItems saveWhat = AllPageItems;
|
||||
if ( canAddAnnotationsNatively() && m_containsExternalAnnotations )
|
||||
saveWhat &= ~AnnotationPageItems; // Don't save local annotations in this case
|
||||
// <page list><page number='x'>.... </page> save pages that hold data
|
||||
QVector< Page * >::const_iterator pIt = m_pagesVector.constBegin(), pEnd = m_pagesVector.constEnd();
|
||||
for ( ; pIt != pEnd; ++pIt )
|
||||
(*pIt)->d->saveLocalContents( pageList, doc );
|
||||
(*pIt)->d->saveLocalContents( pageList, doc, saveWhat );
|
||||
|
||||
// 2.2. Save document info (current viewport, history, ... ) to DOM
|
||||
QDomElement generalInfo = doc.createElement( "generalInfo" );
|
||||
|
@ -1657,12 +1678,16 @@ bool Document::openDocument( const QString & docFile, const KUrl& url, const KMi
|
|||
}
|
||||
|
||||
d->m_generatorName = offer->name();
|
||||
d->m_containsExternalAnnotations = false;
|
||||
d->m_showWarningLimitedAnnotSupport = true;
|
||||
foreach ( Page * p, d->m_pagesVector )
|
||||
{
|
||||
p->d->m_doc = d;
|
||||
if ( !p->annotations().empty() )
|
||||
d->m_containsExternalAnnotations = true;
|
||||
}
|
||||
|
||||
// 2. load Additional Data (our bookmarks and metadata) about the document
|
||||
// 2. load Additional Data (bookmarks, local annotations and metadata) about the document
|
||||
if ( d->m_archiveData )
|
||||
{
|
||||
d->loadDocumentInfo( d->m_archiveData->metadataFileName );
|
||||
|
@ -2331,6 +2356,9 @@ void Document::requestTextPage( uint page )
|
|||
|
||||
void Document::addPageAnnotation( int page, Annotation * annotation )
|
||||
{
|
||||
Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( d->m_generator );
|
||||
AnnotationProxy *proxy = iface ? iface->annotationProxy() : 0;
|
||||
|
||||
// find out the page to attach annotation
|
||||
Page * kp = d->m_pagesVector[ page ];
|
||||
if ( !d->m_generator || !kp )
|
||||
|
@ -2343,42 +2371,160 @@ void Document::addPageAnnotation( int page, Annotation * annotation )
|
|||
// add annotation to the page
|
||||
kp->addAnnotation( annotation );
|
||||
|
||||
// tell the annotation proxy
|
||||
if ( proxy && proxy->supports(AnnotationProxy::Addition) )
|
||||
proxy->notifyAddition( annotation, page );
|
||||
|
||||
// notify observers about the change
|
||||
foreachObserver( notifyPageChanged( page, DocumentObserver::Annotations ) );
|
||||
|
||||
if ( annotation->flags() & Annotation::ExternallyDrawn )
|
||||
{
|
||||
// Redraw everything, including ExternallyDrawn annotations
|
||||
d->refreshPixmaps( page );
|
||||
}
|
||||
|
||||
d->warnLimitedAnnotSupport();
|
||||
}
|
||||
|
||||
void Document::modifyPageAnnotation( int page, Annotation * newannotation )
|
||||
bool Document::canModifyPageAnnotation( const Annotation * annotation ) const
|
||||
{
|
||||
//TODO: modify annotations
|
||||
if ( !annotation || ( annotation->flags() & Annotation::DenyWrite ) )
|
||||
return false;
|
||||
|
||||
if ( !isAllowed(Okular::AllowNotes) )
|
||||
return false;
|
||||
|
||||
if ( ( annotation->flags() & Annotation::External ) && !d->canModifyExternalAnnotations() )
|
||||
return false;
|
||||
|
||||
switch ( annotation->subType() )
|
||||
{
|
||||
case Annotation::AText:
|
||||
case Annotation::ALine:
|
||||
case Annotation::AGeom:
|
||||
case Annotation::AHighlight:
|
||||
case Annotation::AStamp:
|
||||
case Annotation::AInk:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Document::modifyPageAnnotation( int page, Annotation * annotation )
|
||||
{
|
||||
modifyPageAnnotation( page, annotation, true );
|
||||
}
|
||||
|
||||
void Document::modifyPageAnnotation( int page, Annotation * annotation, bool appearanceChanged )
|
||||
{
|
||||
Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( d->m_generator );
|
||||
AnnotationProxy *proxy = iface ? iface->annotationProxy() : 0;
|
||||
|
||||
// find out the page
|
||||
Page * kp = d->m_pagesVector[ page ];
|
||||
if ( !d->m_generator || !kp )
|
||||
return;
|
||||
|
||||
kp->d->modifyAnnotation( newannotation );
|
||||
// tell the annotation proxy
|
||||
if ( proxy && proxy->supports(AnnotationProxy::Modification) )
|
||||
proxy->notifyModification( annotation, page, appearanceChanged );
|
||||
|
||||
// notify observers about the change
|
||||
foreachObserver( notifyPageChanged( page, DocumentObserver::Annotations ) );
|
||||
|
||||
if ( appearanceChanged && (annotation->flags() & Annotation::ExternallyDrawn) )
|
||||
{
|
||||
/* When an annotation is being moved, the generator will not render it.
|
||||
* Therefore there's no need to refresh pixmaps after the first time */
|
||||
if ( annotation->flags() & Annotation::BeingMoved )
|
||||
{
|
||||
if ( d->m_annotationBeingMoved )
|
||||
return;
|
||||
else // First time: take note
|
||||
d->m_annotationBeingMoved = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
d->m_annotationBeingMoved = false;
|
||||
}
|
||||
|
||||
// Redraw everything, including ExternallyDrawn annotations
|
||||
d->refreshPixmaps( page );
|
||||
}
|
||||
|
||||
// If the user is moving the annotation, don't steal the focus
|
||||
if ( (annotation->flags() & Annotation::BeingMoved) == 0 )
|
||||
d->warnLimitedAnnotSupport();
|
||||
}
|
||||
|
||||
bool Document::canRemovePageAnnotation( const Annotation * annotation ) const
|
||||
{
|
||||
if ( !annotation || ( annotation->flags() & Annotation::DenyDelete ) )
|
||||
return false;
|
||||
|
||||
if ( ( annotation->flags() & Annotation::External ) && !d->canRemoveExternalAnnotations() )
|
||||
return false;
|
||||
|
||||
switch ( annotation->subType() )
|
||||
{
|
||||
case Annotation::AText:
|
||||
case Annotation::ALine:
|
||||
case Annotation::AGeom:
|
||||
case Annotation::AHighlight:
|
||||
case Annotation::AStamp:
|
||||
case Annotation::AInk:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Document::removePageAnnotation( int page, Annotation * annotation )
|
||||
{
|
||||
Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( d->m_generator );
|
||||
AnnotationProxy *proxy = iface ? iface->annotationProxy() : 0;
|
||||
bool isExternallyDrawn;
|
||||
|
||||
// find out the page
|
||||
Page * kp = d->m_pagesVector[ page ];
|
||||
if ( !d->m_generator || !kp )
|
||||
return;
|
||||
|
||||
if ( annotation->flags() & Annotation::ExternallyDrawn )
|
||||
isExternallyDrawn = true;
|
||||
else
|
||||
isExternallyDrawn = false;
|
||||
|
||||
// try to remove the annotation
|
||||
if ( kp->removeAnnotation( annotation ) )
|
||||
if ( canRemovePageAnnotation( annotation ) )
|
||||
{
|
||||
// tell the annotation proxy
|
||||
if ( proxy && proxy->supports(AnnotationProxy::Removal) )
|
||||
proxy->notifyRemoval( annotation, page );
|
||||
|
||||
kp->removeAnnotation( annotation ); // Also destroys the object
|
||||
|
||||
// in case of success, notify observers about the change
|
||||
foreachObserver( notifyPageChanged( page, DocumentObserver::Annotations ) );
|
||||
|
||||
if ( isExternallyDrawn )
|
||||
{
|
||||
// Redraw everything, including ExternallyDrawn annotations
|
||||
d->refreshPixmaps( page );
|
||||
}
|
||||
}
|
||||
|
||||
d->warnLimitedAnnotSupport();
|
||||
}
|
||||
|
||||
void Document::removePageAnnotations( int page, const QList< Annotation * > &annotations )
|
||||
{
|
||||
Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( d->m_generator );
|
||||
AnnotationProxy *proxy = iface ? iface->annotationProxy() : 0;
|
||||
bool refreshNeeded = false;
|
||||
|
||||
// find out the page
|
||||
Page * kp = d->m_pagesVector[ page ];
|
||||
if ( !d->m_generator || !kp )
|
||||
|
@ -2387,9 +2533,22 @@ void Document::removePageAnnotations( int page, const QList< Annotation * > &ann
|
|||
bool changed = false;
|
||||
foreach ( Annotation * annotation, annotations )
|
||||
{
|
||||
// try to remove the annotation
|
||||
if ( kp->removeAnnotation( annotation ) )
|
||||
bool isExternallyDrawn;
|
||||
if ( annotation->flags() & Annotation::ExternallyDrawn )
|
||||
isExternallyDrawn = true;
|
||||
else
|
||||
isExternallyDrawn = false;
|
||||
|
||||
if ( canRemovePageAnnotation( annotation ) )
|
||||
{
|
||||
if ( isExternallyDrawn )
|
||||
refreshNeeded = true;
|
||||
|
||||
// tell the annotation proxy
|
||||
if ( proxy && proxy->supports(AnnotationProxy::Removal) )
|
||||
proxy->notifyRemoval( annotation, page );
|
||||
|
||||
kp->removeAnnotation( annotation ); // Also destroys the object
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
@ -2397,7 +2556,48 @@ void Document::removePageAnnotations( int page, const QList< Annotation * > &ann
|
|||
{
|
||||
// in case we removed even only one annotation, notify observers about the change
|
||||
foreachObserver( notifyPageChanged( page, DocumentObserver::Annotations ) );
|
||||
|
||||
if ( refreshNeeded )
|
||||
{
|
||||
// Redraw everything, including ExternallyDrawn annotations
|
||||
d->refreshPixmaps( page );
|
||||
}
|
||||
}
|
||||
|
||||
d->warnLimitedAnnotSupport();
|
||||
}
|
||||
|
||||
bool DocumentPrivate::canAddAnnotationsNatively() const
|
||||
{
|
||||
Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( m_generator );
|
||||
|
||||
if ( iface && iface->supportsOption(Okular::SaveInterface::SaveChanges) &&
|
||||
iface->annotationProxy() && iface->annotationProxy()->supports(AnnotationProxy::Addition) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DocumentPrivate::canModifyExternalAnnotations() const
|
||||
{
|
||||
Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( m_generator );
|
||||
|
||||
if ( iface && iface->supportsOption(Okular::SaveInterface::SaveChanges) &&
|
||||
iface->annotationProxy() && iface->annotationProxy()->supports(AnnotationProxy::Modification) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DocumentPrivate::canRemoveExternalAnnotations() const
|
||||
{
|
||||
Okular::SaveInterface * iface = qobject_cast< Okular::SaveInterface * >( m_generator );
|
||||
|
||||
if ( iface && iface->supportsOption(Okular::SaveInterface::SaveChanges) &&
|
||||
iface->annotationProxy() && iface->annotationProxy()->supports(AnnotationProxy::Removal) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Document::setPageTextSelection( int page, RegularAreaRect * rect, const QColor & color )
|
||||
|
@ -3454,8 +3654,32 @@ bool Document::saveDocumentArchive( const QString &fileName )
|
|||
filesNode.appendChild( metadataFileNameNode );
|
||||
metadataFileNameNode.appendChild( contentDoc.createTextNode( "metadata.xml" ) );
|
||||
|
||||
// If the generator can save annotations natively, do it
|
||||
KTemporaryFile modifiedFile;
|
||||
bool annotationsSavedNatively = false;
|
||||
if ( d->canAddAnnotationsNatively() )
|
||||
{
|
||||
if ( !modifiedFile.open() )
|
||||
return false;
|
||||
|
||||
modifiedFile.close(); // We're only interested in the file name
|
||||
|
||||
QString errorText;
|
||||
if ( saveChanges( modifiedFile.fileName(), &errorText ) )
|
||||
{
|
||||
docPath = modifiedFile.fileName(); // Save this instead of the original file
|
||||
annotationsSavedNatively = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
kWarning(OkularDebug) << "saveChanges failed: " << errorText;
|
||||
kDebug(OkularDebug) << "Falling back to saving a copy of the original file";
|
||||
}
|
||||
}
|
||||
|
||||
KTemporaryFile metadataFile;
|
||||
if ( !d->savePageDocumentInfo( &metadataFile, AnnotationPageItems ) )
|
||||
PageItems saveWhat = annotationsSavedNatively ? None : AnnotationPageItems;
|
||||
if ( !d->savePageDocumentInfo( &metadataFile, saveWhat ) )
|
||||
return false;
|
||||
|
||||
const QByteArray contentDocXml = contentDoc.toByteArray();
|
||||
|
|
|
@ -367,11 +367,39 @@ class OKULAR_EXPORT Document : public QObject
|
|||
*/
|
||||
void addPageAnnotation( int page, Annotation *annotation );
|
||||
|
||||
/**
|
||||
* Tests if the @p annotation can be modified
|
||||
*
|
||||
* @since 0.15 (KDE 4.9)
|
||||
*/
|
||||
bool canModifyPageAnnotation( const Annotation * annotation ) const;
|
||||
|
||||
/**
|
||||
* Modifies the given @p annotation on the given @p page.
|
||||
*
|
||||
* Same as calling modifyPageAnnotation(int,Annotation*,bool) with
|
||||
* appearanceChanged = true
|
||||
*/
|
||||
void modifyPageAnnotation( int page, Annotation *annotation );
|
||||
|
||||
/**
|
||||
* Modifies the given @p annotation on the given @p page.
|
||||
*
|
||||
* The caller can set @p appearanceChanged to false if it didn't change
|
||||
* the annotation appearance (because it only changed non-visible data
|
||||
* such as timestamps or author name).
|
||||
*
|
||||
* @since 0.15 (KDE 4.9)
|
||||
*/
|
||||
void modifyPageAnnotation( int page, Annotation *annotation, bool appearanceChanged );
|
||||
|
||||
/**
|
||||
* Tests if the @p annotation can be removed
|
||||
*
|
||||
* @since 0.15 (KDE 4.9)
|
||||
*/
|
||||
bool canRemovePageAnnotation( const Annotation * annotation ) const;
|
||||
|
||||
/**
|
||||
* Removes the given @p annotation from the given @p page.
|
||||
*/
|
||||
|
|
|
@ -85,7 +85,8 @@ class DocumentPrivate
|
|||
m_scripter( 0 ),
|
||||
m_archiveData( 0 ),
|
||||
m_fontsCached( false ),
|
||||
m_documentInfo( 0 )
|
||||
m_documentInfo( 0 ),
|
||||
m_annotationBeingMoved( false )
|
||||
{
|
||||
calculateMaxTextPages();
|
||||
}
|
||||
|
@ -114,6 +115,10 @@ class DocumentPrivate
|
|||
bool openDocumentInternal( const KService::Ptr& offer, bool isstdin, const QString& docFile, const QByteArray& filedata );
|
||||
bool savePageDocumentInfo( KTemporaryFile *infoFile, int what ) const;
|
||||
DocumentViewport nextDocumentViewport() const;
|
||||
bool canAddAnnotationsNatively() const;
|
||||
bool canModifyExternalAnnotations() const;
|
||||
bool canRemoveExternalAnnotations() const;
|
||||
void warnLimitedAnnotSupport();
|
||||
|
||||
// private slots
|
||||
void saveDocumentInfo() const;
|
||||
|
@ -227,6 +232,10 @@ class DocumentPrivate
|
|||
FontInfo::List m_fontsCache;
|
||||
|
||||
QSet< View * > m_views;
|
||||
|
||||
bool m_annotationBeingMoved; // is an annotation currently being moved?
|
||||
bool m_containsExternalAnnotations; // set on opening and never changed
|
||||
bool m_showWarningLimitedAnnotSupport;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <QtCore/QSet>
|
||||
#include <QtCore/QString>
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QUuid>
|
||||
#include <QtGui/QPixmap>
|
||||
#include <QtXml/QDomDocument>
|
||||
#include <QtXml/QDomElement>
|
||||
|
@ -26,6 +27,8 @@
|
|||
#include "annotations_p.h"
|
||||
#include "area.h"
|
||||
#include "debug_p.h"
|
||||
#include "document.h"
|
||||
#include "document_p.h"
|
||||
#include "form.h"
|
||||
#include "form_p.h"
|
||||
#include "pagecontroller_p.h"
|
||||
|
@ -59,7 +62,7 @@ static void deleteObjectRects( QLinkedList< ObjectRect * >& rects, const QSet<Ob
|
|||
PagePrivate::PagePrivate( Page *page, uint n, double w, double h, Rotation o )
|
||||
: m_page( page ), m_number( n ), m_orientation( o ),
|
||||
m_width( w ), m_height( h ), m_doc( 0 ), m_boundingBox( 0, 0, 1, 1 ),
|
||||
m_rotation( Rotation0 ), m_maxuniqueNum( 0 ),
|
||||
m_rotation( Rotation0 ),
|
||||
m_text( 0 ), m_transition( 0 ), m_textSelections( 0 ),
|
||||
m_openingAction( 0 ), m_closingAction( 0 ), m_duration( -1 ),
|
||||
m_isBoundingBoxKnown( false )
|
||||
|
@ -573,14 +576,10 @@ QColor Page::textSelectionColor() const
|
|||
|
||||
void Page::addAnnotation( Annotation * annotation )
|
||||
{
|
||||
//uniqueName: okular-PAGENUM-ID
|
||||
// Generate uniqueName: okular-{UUID}
|
||||
if(annotation->uniqueName().isEmpty())
|
||||
{
|
||||
QString uniqueName = "okular-";
|
||||
uniqueName += ( QString::number(d->m_number) + '-' + QString::number(++(d->m_maxuniqueNum)) );
|
||||
|
||||
kDebug(OkularDebug).nospace() << "inc m_maxuniqueNum=" << d->m_maxuniqueNum;
|
||||
|
||||
QString uniqueName = "okular-" + QUuid::createUuid().toString();
|
||||
annotation->setUniqueName( uniqueName );
|
||||
}
|
||||
annotation->d_ptr->m_page = d;
|
||||
|
@ -596,37 +595,9 @@ void Page::addAnnotation( Annotation * annotation )
|
|||
m_rects.append( rect );
|
||||
}
|
||||
|
||||
void PagePrivate::modifyAnnotation(Annotation * newannotation )
|
||||
{
|
||||
if(!newannotation)
|
||||
return;
|
||||
|
||||
QLinkedList< Annotation * >::iterator aIt = m_page->m_annotations.begin(), aEnd = m_page->m_annotations.end();
|
||||
for ( ; aIt != aEnd; ++aIt )
|
||||
{
|
||||
if((*aIt)==newannotation)
|
||||
return; //modified already
|
||||
if((*aIt) && (*aIt)->uniqueName()==newannotation->uniqueName())
|
||||
{
|
||||
int rectfound = false;
|
||||
QLinkedList< ObjectRect * >::iterator it = m_page->m_rects.begin(), end = m_page->m_rects.end();
|
||||
for ( ; it != end && !rectfound; ++it )
|
||||
if ( ( (*it)->objectType() == ObjectRect::OAnnotation ) && ( (*it)->object() == (*aIt) ) )
|
||||
{
|
||||
delete *it;
|
||||
*it = new AnnotationObjectRect( newannotation );
|
||||
rectfound = true;
|
||||
}
|
||||
delete *aIt;
|
||||
*aIt = newannotation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Page::removeAnnotation( Annotation * annotation )
|
||||
{
|
||||
if ( !annotation || ( annotation->flags() & Annotation::DenyDelete ) )
|
||||
if ( !d->m_doc->m_parent->canRemovePageAnnotation(annotation) )
|
||||
return false;
|
||||
|
||||
QLinkedList< Annotation * >::iterator aIt = m_annotations.begin(), aEnd = m_annotations.end();
|
||||
|
@ -780,17 +751,7 @@ void PagePrivate::restoreLocalContents( const QDomNode & pageNode )
|
|||
// append annotation to the list or show warning
|
||||
if ( annotation )
|
||||
{
|
||||
annotation->d_ptr->m_page = this;
|
||||
m_page->m_annotations.append( annotation );
|
||||
m_page->m_rects.append( new AnnotationObjectRect( annotation ) );
|
||||
int pos = annotation->uniqueName().lastIndexOf("-");
|
||||
if(pos != -1)
|
||||
{
|
||||
int uniqID=annotation->uniqueName().right(annotation->uniqueName().length()-pos-1).toInt();
|
||||
if ( m_maxuniqueNum < uniqID )
|
||||
m_maxuniqueNum = uniqID;
|
||||
}
|
||||
|
||||
m_doc->m_parent->addPageAnnotation(m_number, annotation);
|
||||
kDebug(OkularDebug) << "restored annot:" << annotation->uniqueName();
|
||||
}
|
||||
else
|
||||
|
|
|
@ -66,13 +66,6 @@ class PagePrivate
|
|||
*/
|
||||
void saveLocalContents( QDomNode & parentNode, QDomDocument & document, PageItems what = AllPageItems ) const;
|
||||
|
||||
/**
|
||||
* Modifies an existing annotation by replacing it with a new @p annotation.
|
||||
*
|
||||
* The unique name is used to find the old annotation.
|
||||
*/
|
||||
void modifyAnnotation( Annotation * annotation );
|
||||
|
||||
/**
|
||||
* Rotates the image and object rects of the page to the given @p orientation.
|
||||
*/
|
||||
|
@ -121,7 +114,6 @@ class PagePrivate
|
|||
DocumentPrivate *m_doc;
|
||||
NormalizedRect m_boundingBox;
|
||||
Rotation m_rotation;
|
||||
int m_maxuniqueNum;
|
||||
|
||||
TextPage * m_text;
|
||||
PageTransition * m_transition;
|
||||
|
|
|
@ -14,7 +14,10 @@
|
|||
#include <qvariant.h>
|
||||
|
||||
#include <core/annotations.h>
|
||||
#include <core/area.h>
|
||||
|
||||
#include "annots.h"
|
||||
#include "generator_pdf.h"
|
||||
#include "popplerembeddedfile.h"
|
||||
#include "config-okular-poppler.h"
|
||||
|
||||
|
@ -32,11 +35,243 @@ static void disposeAnnotation( const Okular::Annotation *ann )
|
|||
delete popplerAnn;
|
||||
}
|
||||
|
||||
static QPointF normPointToPointF( const Okular::NormalizedPoint& pt )
|
||||
{
|
||||
return QPointF(pt.x, pt.y);
|
||||
}
|
||||
|
||||
static QRectF normRectToRectF( const Okular::NormalizedRect& rect )
|
||||
{
|
||||
return QRectF( QPointF(rect.left, rect.top), QPointF(rect.right, rect.bottom) );
|
||||
}
|
||||
|
||||
// Poppler and Okular share the same flag values, but we don't want to export internal flags
|
||||
static int maskExportedFlags(int flags)
|
||||
{
|
||||
return flags & ( Okular::Annotation::Hidden |
|
||||
Okular::Annotation::FixedSize |
|
||||
Okular::Annotation::FixedRotation |
|
||||
Okular::Annotation::DenyPrint |
|
||||
Okular::Annotation::DenyWrite |
|
||||
Okular::Annotation::DenyDelete |
|
||||
Okular::Annotation::ToggleHidingOnMouse );
|
||||
}
|
||||
|
||||
//BEGIN PopplerAnnotationProxy implementation
|
||||
PopplerAnnotationProxy::PopplerAnnotationProxy( Poppler::Document *doc, QMutex *userMutex )
|
||||
: ppl_doc ( doc ), mutex ( userMutex )
|
||||
{
|
||||
}
|
||||
|
||||
PopplerAnnotationProxy::~PopplerAnnotationProxy()
|
||||
{
|
||||
}
|
||||
|
||||
bool PopplerAnnotationProxy::supports( Capability cap ) const
|
||||
{
|
||||
switch ( cap )
|
||||
{
|
||||
#ifdef HAVE_POPPLER_0_20
|
||||
case Addition:
|
||||
case Modification:
|
||||
case Removal:
|
||||
return true;
|
||||
#endif
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void PopplerAnnotationProxy::notifyAddition( Okular::Annotation *okl_ann, int page )
|
||||
{
|
||||
#ifdef HAVE_POPPLER_0_20
|
||||
// Export annotation to DOM
|
||||
QDomDocument doc;
|
||||
QDomElement dom_ann = doc.createElement( "root" );
|
||||
Okular::AnnotationUtils::storeAnnotation( okl_ann, dom_ann, doc );
|
||||
|
||||
QMutexLocker ml(mutex);
|
||||
|
||||
// Create poppler annotation
|
||||
Poppler::Annotation *ppl_ann = Poppler::AnnotationUtils::createAnnotation( dom_ann );
|
||||
|
||||
// Poppler doesn't render StampAnnotations yet
|
||||
if ( ppl_ann->subType() != Poppler::Annotation::AStamp )
|
||||
okl_ann->setFlags( okl_ann->flags() | Okular::Annotation::ExternallyDrawn );
|
||||
|
||||
// Poppler stores highlight points in swapped order
|
||||
if ( ppl_ann->subType() == Poppler::Annotation::AHighlight )
|
||||
{
|
||||
Poppler::HighlightAnnotation * hlann = static_cast<Poppler::HighlightAnnotation*>( ppl_ann );
|
||||
QList<Poppler::HighlightAnnotation::Quad> quads = hlann->highlightQuads();
|
||||
QMutableListIterator<Poppler::HighlightAnnotation::Quad> it( quads );
|
||||
while ( it.hasNext() )
|
||||
{
|
||||
Poppler::HighlightAnnotation::Quad &q = it.next();
|
||||
QPointF t;
|
||||
t = q.points[3];
|
||||
q.points[3] = q.points[0];
|
||||
q.points[0] = t;
|
||||
t = q.points[2];
|
||||
q.points[2] = q.points[1];
|
||||
q.points[1] = t;
|
||||
}
|
||||
hlann->setHighlightQuads( quads );
|
||||
}
|
||||
|
||||
// Bind poppler object to page
|
||||
Poppler::Page *ppl_page = ppl_doc->page( page );
|
||||
ppl_page->addAnnotation( ppl_ann );
|
||||
delete ppl_page;
|
||||
|
||||
// Set pointer to poppler annotation as native Id
|
||||
okl_ann->setNativeId( qVariantFromValue( ppl_ann ) );
|
||||
okl_ann->setDisposeDataFunction( disposeAnnotation );
|
||||
|
||||
kDebug(PDFGenerator::PDFDebug) << okl_ann->uniqueName();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PopplerAnnotationProxy::notifyModification( const Okular::Annotation *okl_ann, int page, bool appearanceChanged )
|
||||
{
|
||||
#ifdef HAVE_POPPLER_0_20
|
||||
Q_UNUSED( page );
|
||||
Q_UNUSED( appearanceChanged );
|
||||
|
||||
Poppler::Annotation *ppl_ann = qvariant_cast<Poppler::Annotation*>( okl_ann->nativeId() );
|
||||
|
||||
if ( !ppl_ann ) // Ignore non-native annotations
|
||||
return;
|
||||
|
||||
QMutexLocker ml(mutex);
|
||||
|
||||
if ( okl_ann->flags() & Okular::Annotation::BeingMoved )
|
||||
{
|
||||
// Okular ui already renders the annotation on its own
|
||||
ppl_ann->setFlags( Poppler::Annotation::Hidden );
|
||||
return;
|
||||
}
|
||||
|
||||
// Set basic properties
|
||||
ppl_ann->setBoundary(normRectToRectF( okl_ann->boundingRectangle() ));
|
||||
ppl_ann->setAuthor( okl_ann->author() );
|
||||
ppl_ann->setContents( okl_ann->contents() );
|
||||
ppl_ann->setFlags(maskExportedFlags( okl_ann->flags() ));
|
||||
|
||||
// Set style
|
||||
Poppler::Annotation::Style s;
|
||||
s.setColor( okl_ann->style().color() );
|
||||
s.setWidth( okl_ann->style().width() );
|
||||
s.setOpacity( okl_ann->style().opacity() );
|
||||
ppl_ann->setStyle( s );
|
||||
|
||||
// Set type-specific properties (if any)
|
||||
switch ( ppl_ann->subType() )
|
||||
{
|
||||
case Poppler::Annotation::AText:
|
||||
{
|
||||
const Okular::TextAnnotation * okl_txtann = static_cast<const Okular::TextAnnotation*>(okl_ann);
|
||||
Poppler::TextAnnotation * ppl_txtann = static_cast<Poppler::TextAnnotation*>(ppl_ann);
|
||||
ppl_txtann->setTextIcon( okl_txtann->textIcon() );
|
||||
ppl_txtann->setTextFont( okl_txtann->textFont() );
|
||||
ppl_txtann->setInplaceAlign( okl_txtann->inplaceAlignment() );
|
||||
if ( okl_txtann->textType() == Okular::TextAnnotation::InPlace )
|
||||
ppl_txtann->setContents( okl_txtann->inplaceText() ); // overrides contents
|
||||
ppl_txtann->setCalloutPoints( QVector<QPointF>() );
|
||||
ppl_txtann->setInplaceIntent( (Poppler::TextAnnotation::InplaceIntent)okl_txtann->inplaceIntent() );
|
||||
break;
|
||||
}
|
||||
case Poppler::Annotation::ALine:
|
||||
{
|
||||
const Okular::LineAnnotation * okl_lineann = static_cast<const Okular::LineAnnotation*>(okl_ann);
|
||||
Poppler::LineAnnotation * ppl_lineann = static_cast<Poppler::LineAnnotation*>(ppl_ann);
|
||||
QLinkedList<QPointF> points;
|
||||
foreach ( const Okular::NormalizedPoint &p, okl_lineann->linePoints() )
|
||||
points.append(normPointToPointF( p ));
|
||||
ppl_lineann->setLinePoints( points );
|
||||
ppl_lineann->setLineStartStyle( (Poppler::LineAnnotation::TermStyle)okl_lineann->lineStartStyle() );
|
||||
ppl_lineann->setLineEndStyle( (Poppler::LineAnnotation::TermStyle)okl_lineann->lineEndStyle() );
|
||||
ppl_lineann->setLineClosed( okl_lineann->lineClosed() );
|
||||
ppl_lineann->setLineInnerColor( okl_lineann->lineInnerColor() );
|
||||
ppl_lineann->setLineLeadingForwardPoint( okl_lineann->lineLeadingForwardPoint() );
|
||||
ppl_lineann->setLineLeadingBackPoint( okl_lineann->lineLeadingBackwardPoint() );
|
||||
ppl_lineann->setLineShowCaption( okl_lineann->showCaption() );
|
||||
ppl_lineann->setLineIntent( (Poppler::LineAnnotation::LineIntent)okl_lineann->lineIntent() );
|
||||
break;
|
||||
}
|
||||
case Poppler::Annotation::AGeom:
|
||||
{
|
||||
const Okular::GeomAnnotation * okl_geomann = static_cast<const Okular::GeomAnnotation*>(okl_ann);
|
||||
Poppler::GeomAnnotation * ppl_geomann = static_cast<Poppler::GeomAnnotation*>(ppl_ann);
|
||||
ppl_geomann->setGeomType( (Poppler::GeomAnnotation::GeomType)okl_geomann->geometricalType() );
|
||||
ppl_geomann->setGeomInnerColor( okl_geomann->geometricalInnerColor() );
|
||||
break;
|
||||
}
|
||||
case Poppler::Annotation::AHighlight:
|
||||
{
|
||||
const Okular::HighlightAnnotation * okl_hlann = static_cast<const Okular::HighlightAnnotation*>(okl_ann);
|
||||
Poppler::HighlightAnnotation * ppl_hlann = static_cast<Poppler::HighlightAnnotation*>(ppl_ann);
|
||||
ppl_hlann->setHighlightType( (Poppler::HighlightAnnotation::HighlightType)okl_hlann->highlightType() );
|
||||
break;
|
||||
}
|
||||
case Poppler::Annotation::AStamp:
|
||||
{
|
||||
const Okular::StampAnnotation * okl_stampann = static_cast<const Okular::StampAnnotation*>(okl_ann);
|
||||
Poppler::StampAnnotation * ppl_stampann = static_cast<Poppler::StampAnnotation*>(ppl_ann);
|
||||
ppl_stampann->setStampIconName( okl_stampann->stampIconName() );
|
||||
break;
|
||||
}
|
||||
case Poppler::Annotation::AInk:
|
||||
{
|
||||
const Okular::InkAnnotation * okl_inkann = static_cast<const Okular::InkAnnotation*>(okl_ann);
|
||||
Poppler::InkAnnotation * ppl_inkann = static_cast<Poppler::InkAnnotation*>(ppl_ann);
|
||||
QList< QLinkedList<QPointF> > paths;
|
||||
foreach ( const QLinkedList<Okular::NormalizedPoint> &path, okl_inkann->inkPaths() )
|
||||
{
|
||||
QLinkedList<QPointF> points;
|
||||
foreach ( const Okular::NormalizedPoint &p, path )
|
||||
points.append(normPointToPointF( p ));
|
||||
paths.append( points );
|
||||
}
|
||||
ppl_inkann->setInkPaths( paths );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
kDebug() << "Type-specific property modification is not implemented for this annotation type";
|
||||
break;
|
||||
}
|
||||
|
||||
kDebug(PDFGenerator::PDFDebug) << okl_ann->uniqueName();
|
||||
#endif
|
||||
}
|
||||
|
||||
void PopplerAnnotationProxy::notifyRemoval( Okular::Annotation *okl_ann, int page )
|
||||
{
|
||||
#ifdef HAVE_POPPLER_0_20
|
||||
Poppler::Annotation *ppl_ann = qvariant_cast<Poppler::Annotation*>( okl_ann->nativeId() );
|
||||
|
||||
if ( !ppl_ann ) // Ignore non-native annotations
|
||||
return;
|
||||
|
||||
QMutexLocker ml(mutex);
|
||||
|
||||
Poppler::Page *ppl_page = ppl_doc->page( page );
|
||||
ppl_page->removeAnnotation( ppl_ann ); // Also destroys ppl_ann
|
||||
delete ppl_page;
|
||||
|
||||
okl_ann->setNativeId( qVariantFromValue(0) ); // So that we don't double-free in disposeAnnotation
|
||||
|
||||
kDebug(PDFGenerator::PDFDebug) << okl_ann->uniqueName();
|
||||
#endif
|
||||
}
|
||||
//END PopplerAnnotationProxy implementation
|
||||
|
||||
Okular::Annotation* createAnnotationFromPopplerAnnotation( Poppler::Annotation *ann, bool *doDelete )
|
||||
{
|
||||
Okular::Annotation *annotation = 0;
|
||||
*doDelete = true;
|
||||
bool tieToOkularAnn = false;
|
||||
bool externallyDrawn = false;
|
||||
switch ( ann->subType() )
|
||||
{
|
||||
case Poppler::Annotation::AFileAttachment:
|
||||
|
@ -86,6 +321,21 @@ Okular::Annotation* createAnnotationFromPopplerAnnotation( Poppler::Annotation *
|
|||
|
||||
break;
|
||||
}
|
||||
case Poppler::Annotation::AText:
|
||||
case Poppler::Annotation::ALine:
|
||||
case Poppler::Annotation::AGeom:
|
||||
case Poppler::Annotation::AHighlight:
|
||||
case Poppler::Annotation::AInk:
|
||||
{
|
||||
externallyDrawn = true;
|
||||
/* fallback */
|
||||
}
|
||||
case Poppler::Annotation::AStamp:
|
||||
{
|
||||
tieToOkularAnn = true;
|
||||
*doDelete = false;
|
||||
/* fallback */
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
{
|
||||
|
@ -95,7 +345,7 @@ Okular::Annotation* createAnnotationFromPopplerAnnotation( Poppler::Annotation *
|
|||
doc.appendChild( root );
|
||||
Poppler::AnnotationUtils::storeAnnotation( ann, root, doc );
|
||||
annotation = Okular::AnnotationUtils::createAnnotation( root );
|
||||
return annotation;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ( annotation )
|
||||
|
@ -107,6 +357,27 @@ Okular::Annotation* createAnnotationFromPopplerAnnotation( Poppler::Annotation *
|
|||
annotation->setCreationDate( ann->creationDate() );
|
||||
annotation->setFlags( ann->flags() );
|
||||
annotation->setBoundingRectangle( Okular::NormalizedRect::fromQRectF( ann->boundary() ) );
|
||||
|
||||
if (externallyDrawn)
|
||||
annotation->setFlags( annotation->flags() | Okular::Annotation::ExternallyDrawn );
|
||||
|
||||
// Poppler stores highlight points in swapped order
|
||||
if ( annotation->subType() == Okular::Annotation::AHighlight )
|
||||
{
|
||||
Okular::HighlightAnnotation * hlann = static_cast<Okular::HighlightAnnotation*>( annotation );
|
||||
QList<Okular::HighlightAnnotation::Quad> &quads = hlann->highlightQuads();
|
||||
for (QList<Okular::HighlightAnnotation::Quad>::iterator it = quads.begin(); it != quads.end(); ++it)
|
||||
{
|
||||
Okular::NormalizedPoint t;
|
||||
t = it->point( 3 );
|
||||
it->setPoint( it->point(0), 3 );
|
||||
it->setPoint( t, 0 );
|
||||
t = it->point( 2 );
|
||||
it->setPoint( it->point(1), 2 );
|
||||
it->setPoint( t, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
// TODO clone style
|
||||
// TODO clone window
|
||||
// TODO clone revisions
|
||||
|
|
38
generators/poppler/annots.h
Normal file
38
generators/poppler/annots.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/***************************************************************************
|
||||
* Copyright (C) 2012 by Fabio D'Urso <fabiodurso@hotmail.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. *
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef _OKULAR_GENERATOR_PDF_ANNOTS_H_
|
||||
#define _OKULAR_GENERATOR_PDF_ANNOTS_H_
|
||||
|
||||
#include <poppler-annotation.h>
|
||||
#include <poppler-qt4.h>
|
||||
|
||||
#include <qmutex.h>
|
||||
|
||||
#include "core/annotations.h"
|
||||
#include "config-okular-poppler.h"
|
||||
|
||||
extern Okular::Annotation* createAnnotationFromPopplerAnnotation( Poppler::Annotation *ann, bool * doDelete );
|
||||
|
||||
class PopplerAnnotationProxy : public Okular::AnnotationProxy
|
||||
{
|
||||
public:
|
||||
PopplerAnnotationProxy( Poppler::Document *doc, QMutex *userMutex );
|
||||
~PopplerAnnotationProxy();
|
||||
|
||||
bool supports( Capability capability ) const;
|
||||
void notifyAddition( Okular::Annotation *annotation, int page );
|
||||
void notifyModification( const Okular::Annotation *annotation, int page, bool appearanceChanged );
|
||||
void notifyRemoval( Okular::Annotation *annotation, int page );
|
||||
private:
|
||||
Poppler::Document *ppl_doc;
|
||||
QMutex *mutex;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -52,6 +52,7 @@
|
|||
# include <poppler-media.h>
|
||||
#endif
|
||||
|
||||
#include "annots.h"
|
||||
#include "formfields.h"
|
||||
#include "popplerembeddedfile.h"
|
||||
|
||||
|
@ -61,7 +62,6 @@ Q_DECLARE_METATYPE(Poppler::FontInfo)
|
|||
Q_DECLARE_METATYPE(const Poppler::LinkMovie*)
|
||||
#endif
|
||||
|
||||
static const int PDFDebug = 4710;
|
||||
static const int defaultPageWidth = 595;
|
||||
static const int defaultPageHeight = 842;
|
||||
|
||||
|
@ -72,11 +72,30 @@ class PDFOptionsPage : public QWidget
|
|||
{
|
||||
setWindowTitle( i18n( "PDF Options" ) );
|
||||
QVBoxLayout *layout = new QVBoxLayout(this);
|
||||
m_printAnnots = new QCheckBox(i18n("Print annotations"), this);
|
||||
m_printAnnots->setToolTip(i18n("Include annotations in the printed document"));
|
||||
m_printAnnots->setWhatsThis(i18n("Includes annotations in the printed document. You can disable this if you want to print the original unannotated document."));
|
||||
layout->addWidget(m_printAnnots);
|
||||
m_forceRaster = new QCheckBox(i18n("Force rasterization"), this);
|
||||
m_forceRaster->setToolTip(i18n("Rasterize into an image before printing"));
|
||||
m_forceRaster->setWhatsThis(i18n("Forces the rasterization of each page into an image before printing it. This usually gives somewhat worse results, but is useful when printing documents that appear to print incorrectly."));
|
||||
layout->addWidget(m_forceRaster);
|
||||
layout->addStretch(1);
|
||||
|
||||
#ifndef HAVE_POPPLER_0_20
|
||||
m_printAnnots->setVisible( false );
|
||||
#endif
|
||||
setPrintAnnots( true ); // Default value
|
||||
}
|
||||
|
||||
bool printAnnots()
|
||||
{
|
||||
return m_printAnnots->isChecked();
|
||||
}
|
||||
|
||||
void setPrintAnnots( bool printAnnots )
|
||||
{
|
||||
m_printAnnots->setChecked( printAnnots );
|
||||
}
|
||||
|
||||
bool printForceRaster()
|
||||
|
@ -90,6 +109,7 @@ class PDFOptionsPage : public QWidget
|
|||
}
|
||||
|
||||
private:
|
||||
QCheckBox *m_printAnnots;
|
||||
QCheckBox *m_forceRaster;
|
||||
};
|
||||
|
||||
|
@ -317,8 +337,6 @@ static QLinkedList<Okular::ObjectRect*> generateLinks( const QList<Poppler::Link
|
|||
return links;
|
||||
}
|
||||
|
||||
extern Okular::Annotation* createAnnotationFromPopplerAnnotation( Poppler::Annotation *ann, bool * doDelete );
|
||||
|
||||
/** NOTES on threading:
|
||||
* internal: thread race prevention is done via the 'docLock' mutex. the
|
||||
* mutex is needed only because we have the asynchronous thread; else
|
||||
|
@ -364,7 +382,7 @@ PDFGenerator::PDFGenerator( QObject *parent, const QVariantList &args )
|
|||
docInfoDirty( true ), docSynopsisDirty( true ),
|
||||
docEmbeddedFilesDirty( true ), nextFontPage( 0 ),
|
||||
dpiX( 72.0 /*Okular::Utils::dpiX()*/ ), dpiY( 72.0 /*Okular::Utils::dpiY()*/ ),
|
||||
synctex_scanner(0)
|
||||
annotProxy( 0 ), synctex_scanner( 0 )
|
||||
{
|
||||
setFeature( Threaded );
|
||||
setFeature( TextExtraction );
|
||||
|
@ -513,6 +531,9 @@ bool PDFGenerator::init(QVector<Okular::Page*> & pagesVector, const QString &wal
|
|||
// update the configuration
|
||||
reparseConfig();
|
||||
|
||||
// create annotation proxy
|
||||
annotProxy = new PopplerAnnotationProxy( pdfdoc, userMutex() );
|
||||
|
||||
// the file has been loaded correctly
|
||||
return true;
|
||||
}
|
||||
|
@ -521,6 +542,8 @@ bool PDFGenerator::doCloseDocument()
|
|||
{
|
||||
// remove internal objects
|
||||
userMutex()->lock();
|
||||
delete annotProxy;
|
||||
annotProxy = 0;
|
||||
delete pdfdoc;
|
||||
pdfdoc = 0;
|
||||
userMutex()->unlock();
|
||||
|
@ -1026,9 +1049,11 @@ bool PDFGenerator::print( QPrinter& printer )
|
|||
pstitle = document()->currentDocument().fileName();
|
||||
}
|
||||
|
||||
bool printAnnots = true;
|
||||
bool forceRasterize = false;
|
||||
if ( pdfOptionsPage )
|
||||
{
|
||||
printAnnots = pdfOptionsPage->printAnnots();
|
||||
forceRasterize = pdfOptionsPage->printForceRaster();
|
||||
}
|
||||
|
||||
|
@ -1047,6 +1072,11 @@ bool PDFGenerator::print( QPrinter& printer )
|
|||
psConverter->setForceRasterize(forceRasterize);
|
||||
psConverter->setTitle(pstitle);
|
||||
|
||||
#ifdef HAVE_POPPLER_0_20
|
||||
if (!printAnnots)
|
||||
psConverter->setPSOptions(psConverter->psOptions() | Poppler::PSConverter::HideAnnotations );
|
||||
#endif
|
||||
|
||||
userMutex()->lock();
|
||||
if (psConverter->convert())
|
||||
{
|
||||
|
@ -1724,7 +1754,11 @@ bool PDFGenerator::supportsOption( SaveOption option ) const
|
|||
switch ( option )
|
||||
{
|
||||
case SaveChanges:
|
||||
return true;
|
||||
{
|
||||
QMutexLocker locker( userMutex() );
|
||||
// Saving files with /Encrypt is not supported
|
||||
return pdfdoc->isEncrypted() ? false : true;
|
||||
}
|
||||
default: ;
|
||||
}
|
||||
return false;
|
||||
|
@ -1764,6 +1798,11 @@ bool PDFGenerator::save( const QString &fileName, SaveOptions options, QString *
|
|||
return success;
|
||||
}
|
||||
|
||||
Okular::AnnotationProxy* PDFGenerator::annotationProxy() const
|
||||
{
|
||||
return annotProxy;
|
||||
}
|
||||
|
||||
#include "generator_pdf.moc"
|
||||
|
||||
/* kate: replace-tabs on; indent-width 4; */
|
||||
|
|
|
@ -32,6 +32,7 @@ class SourceReference;
|
|||
}
|
||||
|
||||
class PDFOptionsPage;
|
||||
class PopplerAnnotationProxy;
|
||||
|
||||
/**
|
||||
* @short A generator that builds contents from a PDF document.
|
||||
|
@ -56,6 +57,8 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p
|
|||
PDFGenerator( QObject *parent, const QVariantList &args );
|
||||
virtual ~PDFGenerator();
|
||||
|
||||
static const int PDFDebug = 4710;
|
||||
|
||||
// [INHERITED] load a document and fill up the pagesVector
|
||||
bool loadDocument( const QString & fileName, QVector<Okular::Page*> & pagesVector );
|
||||
bool loadDocumentFromData( const QByteArray & fileData, QVector<Okular::Page*> & pagesVector );
|
||||
|
@ -93,6 +96,7 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p
|
|||
// [INHERITED] save interface
|
||||
bool supportsOption( SaveOption ) const;
|
||||
bool save( const QString &fileName, SaveOptions options, QString *errorText );
|
||||
Okular::AnnotationProxy* annotationProxy() const;
|
||||
|
||||
protected:
|
||||
bool doCloseDocument();
|
||||
|
@ -142,6 +146,7 @@ class PDFGenerator : public Okular::Generator, public Okular::ConfigInterface, p
|
|||
int nextFontPage;
|
||||
double dpiX;
|
||||
double dpiY;
|
||||
PopplerAnnotationProxy *annotProxy;
|
||||
QHash<Okular::Annotation*, Poppler::Annotation*> annotationsHash;
|
||||
|
||||
QBitArray rectsGenerated;
|
||||
|
|
|
@ -65,11 +65,21 @@ class OKULAR_EXPORT SaveInterface
|
|||
* Save to the specified @p fileName with the specified @p options.
|
||||
*/
|
||||
virtual bool save( const QString &fileName, SaveOptions options, QString *errorText ) = 0;
|
||||
|
||||
/**
|
||||
* Returns the annotation proxy. Generators can return NULL if native
|
||||
* annotations are not supported.
|
||||
*
|
||||
* @note Returning NULL is equivalent to returning an AnnotationProxy
|
||||
* that doesn't support any capability.
|
||||
* @since 0.15 (KDE 4.9)
|
||||
*/
|
||||
virtual AnnotationProxy* annotationProxy() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Q_DECLARE_INTERFACE( Okular::SaveInterface, "org.kde.okular.SaveInterface/0.2" )
|
||||
Q_DECLARE_INTERFACE( Okular::SaveInterface, "org.kde.okular.SaveInterface/0.3" )
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS( Okular::SaveInterface::SaveOptions )
|
||||
|
||||
#endif
|
||||
|
|
|
@ -53,8 +53,11 @@ void AnnotationPopup::exec( const QPoint &point )
|
|||
deleteNote->setEnabled( mDocument->isAllowed( Okular::AllowNotes ) );
|
||||
|
||||
const AnnotPagePair &firstAnnotPagePair = mAnnotations.at(0);
|
||||
if ( onlyOne && firstAnnotPagePair.annotation->flags() & Okular::Annotation::DenyDelete )
|
||||
deleteNote->setEnabled( false );
|
||||
foreach ( const AnnotPagePair& pair, mAnnotations )
|
||||
{
|
||||
if ( !mDocument->canRemovePageAnnotation(pair.annotation) )
|
||||
deleteNote->setEnabled( false );
|
||||
}
|
||||
|
||||
showProperties = menu.addAction( KIcon( "configure" ), i18n( "&Properties" ) );
|
||||
showProperties->setEnabled( onlyOne );
|
||||
|
|
|
@ -34,7 +34,7 @@ AnnotsPropertiesDialog::AnnotsPropertiesDialog( QWidget *parent, Okular::Documen
|
|||
{
|
||||
setFaceType( Tabbed );
|
||||
m_annot=ann;
|
||||
bool canEditAnnotations = !(ann->flags() & Okular::Annotation::External) && m_document->isAllowed( Okular::AllowNotes );
|
||||
const bool canEditAnnotations = m_document->canModifyPageAnnotation( ann );
|
||||
setCaptionTextbyAnnotType();
|
||||
if ( canEditAnnotations )
|
||||
{
|
||||
|
|
|
@ -190,6 +190,8 @@ AnnotWindow::AnnotWindow( QWidget * parent, Okular::Annotation * annot, Okular::
|
|||
setFrameStyle( Panel | Raised );
|
||||
setAttribute( Qt::WA_DeleteOnClose );
|
||||
|
||||
const bool canEditAnnotation = m_document->canModifyPageAnnotation( annot );
|
||||
|
||||
textEdit = new KTextEdit( this );
|
||||
textEdit->setAcceptRichText( false );
|
||||
textEdit->setPlainText( GuiUtils::contents( m_annot ) );
|
||||
|
@ -197,6 +199,9 @@ AnnotWindow::AnnotWindow( QWidget * parent, Okular::Annotation * annot, Okular::
|
|||
connect(textEdit,SIGNAL(textChanged()),
|
||||
this,SLOT(slotsaveWindowText()));
|
||||
|
||||
if (!canEditAnnotation)
|
||||
textEdit->setReadOnly(true);
|
||||
|
||||
m_latexRenderer = new GuiUtils::LatexRenderer();
|
||||
emit containsLatex( GuiUtils::LatexRenderer::mightContainLatex( GuiUtils::contents( m_annot ) ) );
|
||||
|
||||
|
@ -276,30 +281,47 @@ void AnnotWindow::slotOptionBtn()
|
|||
void AnnotWindow::slotsaveWindowText()
|
||||
{
|
||||
const QString newText = textEdit->toPlainText();
|
||||
|
||||
// 0. tell the document
|
||||
m_document->modifyPageAnnotation( m_page, m_annot );
|
||||
bool appearanceChanged = false;
|
||||
|
||||
// 1. window text
|
||||
// Set window text
|
||||
if ( !m_annot->window().text().isEmpty() )
|
||||
{
|
||||
m_annot->window().setText( newText );
|
||||
return;
|
||||
}
|
||||
// 2. if Text and InPlace, the inplace text
|
||||
if ( m_annot->subType() == Okular::Annotation::AText )
|
||||
|
||||
// Handle special cases
|
||||
switch ( m_annot->subType() )
|
||||
{
|
||||
Okular::TextAnnotation * txtann = static_cast< Okular::TextAnnotation * >( m_annot );
|
||||
if ( txtann->textType() == Okular::TextAnnotation::InPlace )
|
||||
// If it's an in-place TextAnnotation, set the inplace text
|
||||
case Okular::Annotation::AText:
|
||||
{
|
||||
txtann->setInplaceText( newText );
|
||||
return;
|
||||
Okular::TextAnnotation * txtann = static_cast< Okular::TextAnnotation * >( m_annot );
|
||||
if ( txtann->textType() == Okular::TextAnnotation::InPlace )
|
||||
{
|
||||
txtann->setInplaceText( newText );
|
||||
appearanceChanged = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// If it's a LineAnnotation, check if caption text is visible
|
||||
case Okular::Annotation::ALine:
|
||||
{
|
||||
Okular::LineAnnotation * lineann = static_cast< Okular::LineAnnotation * >( m_annot );
|
||||
if ( lineann->showCaption() )
|
||||
appearanceChanged = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// 3. contents
|
||||
// Set contents
|
||||
m_annot->setContents( newText );
|
||||
|
||||
// Tell the document
|
||||
m_document->modifyPageAnnotation( m_page, m_annot, appearanceChanged );
|
||||
|
||||
emit containsLatex( GuiUtils::LatexRenderer::mightContainLatex( newText ) );
|
||||
}
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
|
|||
QList< QPair<QColor, Okular::NormalizedRect> > * bufferedHighlights = 0;
|
||||
QList< Okular::Annotation * > * bufferedAnnotations = 0;
|
||||
QList< Okular::Annotation * > * unbufferedAnnotations = 0;
|
||||
Okular::Annotation *boundingRectOnlyAnn = 0; // Paint the bounding rect of this annotation
|
||||
// fill up lists with visible annotation/highlight objects/text selections
|
||||
if ( canDrawHighlights || canDrawTextSelection || canDrawAnnotations )
|
||||
{
|
||||
|
@ -169,9 +170,20 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
|
|||
for ( ; aIt != aEnd; ++aIt )
|
||||
{
|
||||
Okular::Annotation * ann = *aIt;
|
||||
if ( ann->flags() & ( Okular::Annotation::Hidden | Okular::Annotation::ExternallyDrawn ) )
|
||||
int flags = ann->flags();
|
||||
|
||||
if ( flags & Okular::Annotation::Hidden )
|
||||
continue;
|
||||
|
||||
if ( flags & Okular::Annotation::ExternallyDrawn )
|
||||
{
|
||||
// ExternallyDrawn annots are never rendered by PagePainter.
|
||||
// Just paint the boundingRect if the annot is BeingMoved
|
||||
if ( flags & Okular::Annotation::BeingMoved )
|
||||
boundingRectOnlyAnn = ann;
|
||||
continue;
|
||||
}
|
||||
|
||||
bool intersects = ann->transformedBoundingRectangle().intersects( nXMin, nYMin, nXMax, nYMax );
|
||||
if ( ann->subType() == Okular::Annotation::AText )
|
||||
{
|
||||
|
@ -703,6 +715,13 @@ void PagePainter::paintCroppedPageOnPainter( QPainter * destPainter, const Okula
|
|||
}
|
||||
}
|
||||
|
||||
if ( boundingRectOnlyAnn )
|
||||
{
|
||||
QRect annotBoundary = boundingRectOnlyAnn->transformedBoundingRectangle().geometry( scaledWidth, scaledHeight ).translated( -scaledCrop.topLeft() );
|
||||
mixedPainter->setPen( Qt::DashLine );
|
||||
mixedPainter->drawRect( annotBoundary );
|
||||
}
|
||||
|
||||
/** 6 -- MIXED FLOW. Draw LINKS+IMAGES BORDER on ACTIVE PAINTER **/
|
||||
if ( enhanceLinks || enhanceImages )
|
||||
{
|
||||
|
|
|
@ -132,6 +132,7 @@ public:
|
|||
bool mouseOnRect;
|
||||
Okular::Annotation * mouseAnn;
|
||||
QPoint mouseAnnPos;
|
||||
int mouseAnnPageNum;
|
||||
|
||||
// table selection
|
||||
QList<double> tableSelectionCols;
|
||||
|
@ -1793,7 +1794,7 @@ void PageView::mouseMoveEvent( QMouseEvent * e )
|
|||
}
|
||||
d->mouseAnn->translate( Okular::NormalizedPoint( pf.x(), pf.y() ) );
|
||||
d->mouseAnnPos = newpos;
|
||||
d->document->modifyPageAnnotation( pageItem->pageNumber(), d->mouseAnn );
|
||||
d->document->modifyPageAnnotation( d->mouseAnnPageNum, d->mouseAnn );
|
||||
}
|
||||
}
|
||||
// drag page
|
||||
|
@ -1965,11 +1966,17 @@ void PageView::mousePressEvent( QMouseEvent * e )
|
|||
if ( d->mouseAnn && !d->mouseAnn->canBeMoved() )
|
||||
d->mouseAnn = 0;
|
||||
}
|
||||
if ( !d->mouseAnn )
|
||||
if ( d->mouseAnn )
|
||||
{
|
||||
d->mouseGrabPos = d->mouseOnRect ? QPoint() : d->mousePressPos;
|
||||
if ( !d->mouseOnRect )
|
||||
d->leftClickTimer.start( QApplication::doubleClickInterval() + 10 );
|
||||
d->mouseAnn->setFlags( d->mouseAnn->flags() | Okular::Annotation::BeingMoved );
|
||||
d->mouseAnnPageNum = pageItem->pageNumber();
|
||||
d->document->modifyPageAnnotation( d->mouseAnnPageNum, d->mouseAnn );
|
||||
}
|
||||
else
|
||||
{
|
||||
d->mouseGrabPos = d->mouseOnRect ? QPoint() : d->mousePressPos;
|
||||
if ( !d->mouseOnRect )
|
||||
d->leftClickTimer.start( QApplication::doubleClickInterval() + 10 );
|
||||
}
|
||||
}
|
||||
else if ( rightButton )
|
||||
|
@ -2145,6 +2152,9 @@ void PageView::mouseReleaseEvent( QMouseEvent * e )
|
|||
|
||||
if ( d->mouseAnn )
|
||||
{
|
||||
// Just finished to move the annotation
|
||||
d->mouseAnn->setFlags( d->mouseAnn->flags() & ~Okular::Annotation::BeingMoved );
|
||||
d->document->modifyPageAnnotation( d->mouseAnnPageNum, d->mouseAnn );
|
||||
setCursor( Qt::ArrowCursor );
|
||||
d->mouseAnn = 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue