diff --git a/core/annotations.h b/core/annotations.h index 25a168764..d5771c8cc 100644 --- a/core/annotations.h +++ b/core/annotations.h @@ -1,1731 +1,1737 @@ /*************************************************************************** * Copyright (C) 2005 by Enrico Ros * * * * 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_ANNOTATIONS_H_ #define _OKULAR_ANNOTATIONS_H_ #include #include #include #include #include #include #include #include "okularcore_export.h" #include "area.h" namespace Okular { class Action; class Annotation; class AnnotationObjectRect; class AnnotationPrivate; class Document; class EmbeddedFile; class Page; class PagePrivate; class Sound; class Movie; class TextAnnotationPrivate; class LineAnnotationPrivate; class GeomAnnotationPrivate; class HighlightAnnotationPrivate; class StampAnnotationPrivate; class InkAnnotationPrivate; class CaretAnnotationPrivate; class FileAttachmentAnnotationPrivate; class SoundAnnotationPrivate; class MovieAnnotationPrivate; class ScreenAnnotationPrivate; class WidgetAnnotationPrivate; class RichMediaAnnotationPrivate; /** * @short Helper class for (recursive) annotation retrieval/storage. */ class OKULARCORE_EXPORT AnnotationUtils { public: /** * Restore an annotation (with revisions if needed) from the dom @p element. * * Returns a pointer to the complete annotation or 0 if element is invalid. */ static Annotation * createAnnotation( const QDomElement & element ); /** * Saves the @p annotation as a child of @p element taking * care of saving all revisions if it has any. */ static void storeAnnotation( const Annotation * annotation, QDomElement & element, QDomDocument & document ); /** * Returns the child element with the given @p name from the direct * children of @p parentNode or a null element if not found. */ static QDomElement findChildElement( const QDomNode & parentNode, const QString & name ); /** * Returns the geometry of the given @p annotation scaled by * @p scaleX and @p scaleY. */ static QRect annotationGeometry( const Annotation * annotation, double scaleX, double scaleY ); }; /** * @short Annotation struct holds properties shared by all annotations. * * An Annotation is an object (text note, highlight, sound, popup window, ..) * contained by a Page in the document. */ class OKULARCORE_EXPORT Annotation { /// @cond PRIVATE friend class AnnotationObjectRect; friend class Document; friend class DocumentPrivate; friend class ObjectRect; friend class Page; friend class PagePrivate; /// @endcond public: /** * Describes the type of annotation as defined in PDF standard. */ enum SubType { AText = 1, ///< A textual annotation ALine = 2, ///< A line annotation AGeom = 3, ///< A geometrical annotation AHighlight = 4, ///< A highlight annotation AStamp = 5, ///< A stamp annotation AInk = 6, ///< An ink annotation ACaret = 8, ///< A caret annotation AFileAttachment = 9, ///< A file attachment annotation ASound = 10, ///< A sound annotation AMovie = 11, ///< A movie annotation AScreen = 12, ///< A screen annotation AWidget = 13, ///< A widget annotation ARichMedia = 14,///< A rich media annotation A_BASE = 0 ///< The annotation base class }; /** * Describes additional properties of an annotation. */ enum Flag { Hidden = 1, ///< Is not shown in the document FixedSize = 2, ///< Has a fixed size FixedRotation = 4, ///< Has a fixed rotation DenyPrint = 8, ///< Cannot be printed DenyWrite = 16, ///< Cannot be changed DenyDelete = 32, ///< Cannot be deleted ToggleHidingOnMouse = 64, ///< Can be hidden/shown by mouse click External = 128, ///< Is stored external 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) BeingResized = 1024 ///< Is being resized (mouse drag and drop). If ExternallyDrawn, the generator must not draw it @since 1.1.0 }; /** * Describes possible line styles for @see ALine annotation. */ enum LineStyle { Solid = 1, ///< A solid line Dashed = 2, ///< A dashed line Beveled = 4, ///< A beveled line Inset = 8, ///< A inseted line Underline = 16 ///< An underline }; /** * Describes possible line effects for @see ALine annotation. */ enum LineEffect { NoEffect = 1, ///< No effect Cloudy = 2 ///< The cloudy effect }; /** * Describes the scope of revision information. */ enum RevisionScope { Reply = 1, ///< Belongs to a reply Group = 2, ///< Belongs to a group Delete = 4 ///< Belongs to a deleted paragraph }; /** * Describes the type of revision information. */ enum RevisionType { None = 1, ///< Not specified Marked = 2, ///< Is marked Unmarked = 4, ///< Is unmarked Accepted = 8, ///< Has been accepted Rejected = 16, ///< Was rejected Cancelled = 32, ///< Has been cancelled Completed = 64 ///< Has been completed }; /** * Describes the type of additional actions. * * @since 0.16 (KDE 4.10) */ enum AdditionalActionType { - PageOpening, ///< Performed when the page containing the annotation is opened. - PageClosing ///< Performed when the page containing the annotation is closed. + PageOpening, ///< Performed when the page containing the annotation is opened. + PageClosing, ///< Performed when the page containing the annotation is closed. + CursorEntering, ///< Performed when the cursor enters the annotation's active area @since 1.5 + CursorLeaving, ///< Performed when the cursor exists the annotation's active area @since 1.5 + MousePressed, ///< Performed when the mouse button is pressed inside the annotation's active area @since 1.5 + MouseReleased, ///< Performed when the mouse button is released inside the annotation's active area @since 1.5 + FocusIn, ///< Performed when the annotation receives the input focus @since 1.5 + FocusOut, ///< Performed when the annotation loses the input focus @since 1.5 }; /** * A function to be called when the annotation is destroyed. * * @warning the function must *not* call any virtual function, * nor subcast. * * @since 0.7 (KDE 4.1) */ typedef void ( * DisposeDataFunction )( const Okular::Annotation * ); /** * Destroys the annotation. */ virtual ~Annotation(); /** * Sets the @p author of the annotation. */ void setAuthor( const QString &author ); /** * Returns the author of the annotation. */ QString author() const; /** * Sets the @p contents of the annotation. */ void setContents( const QString &contents ); /** * Returns the contents of the annotation. */ QString contents() const; /** * Sets the unique @p name of the annotation. */ void setUniqueName( const QString &name ); /** * Returns the unique name of the annotation. */ QString uniqueName() const; /** * Sets the last modification @p date of the annotation. * * The date must be before or equal to QDateTime::currentDateTime() */ void setModificationDate( const QDateTime &date ); /** * Returns the last modification date of the annotation. */ QDateTime modificationDate() const; /** * Sets the creation @p date of the annotation. * * The date must be before or equal to @see modificationDate() */ void setCreationDate( const QDateTime &date ); /** * Returns the creation date of the annotation. */ QDateTime creationDate() const; /** * Sets the @p flags of the annotation. * @see @ref Flag */ void setFlags( int flags ); /** * Returns the flags of the annotation. * @see @ref Flag */ int flags() const; /** * Sets the bounding @p rectangle of the annotation. */ void setBoundingRectangle( const NormalizedRect &rectangle ); /** * Returns the bounding rectangle of the annotation. */ NormalizedRect boundingRectangle() const; /** * Returns the transformed bounding rectangle of the annotation. * * This rectangle must be used when showing annotations on screen * to have them rotated correctly. */ NormalizedRect transformedBoundingRectangle() const; /** * Move the annotation by the specified coordinates. * * @see canBeMoved() */ void translate( const NormalizedPoint &coord ); /** * Adjust the annotation by the specified coordinates. * Adds coordinates of @p deltaCoord1 to annotations top left corner, * and @p deltaCoord2 to the bottom right. * * @see canBeResized() */ void adjust( const NormalizedPoint & deltaCoord1, const NormalizedPoint & deltaCoord2 ); /** * The Style class contains all information about style of the * annotation. */ class OKULARCORE_EXPORT Style { public: /** * Creates a new style. */ Style(); /** * Destroys the style. */ ~Style(); Style( const Style &other ); Style& operator=( const Style &other ); /** * Sets the @p color of the style. */ void setColor( const QColor &color ); /** * Returns the color of the style. */ QColor color() const; /** * Sets the @p opacity of the style. */ void setOpacity( double opacity ); /** * Returns the opacity of the style. */ double opacity() const; /** * Sets the @p width of the style. */ void setWidth( double width ); /** * Returns the width of the style. */ double width() const; /** * Sets the line @p style of the style. */ void setLineStyle( LineStyle style ); /** * Returns the line style of the style. */ LineStyle lineStyle() const; /** * Sets the x-corners of the style. */ void setXCorners( double xCorners ); /** * Returns the x-corners of the style. */ double xCorners() const; /** * Sets the y-corners of the style. */ void setYCorners( double yCorners ); /** * Returns the y-corners of the style. */ double yCorners() const; /** * Sets the @p marks of the style. */ void setMarks( int marks ); /** * Returns the marks of the style. */ int marks() const; /** * Sets the @p spaces of the style. */ void setSpaces( int spaces ); /** * Returns the spaces of the style. */ int spaces() const; /** * Sets the line @p effect of the style. */ void setLineEffect( LineEffect effect ); /** * Returns the line effect of the style. */ LineEffect lineEffect() const; /** * Sets the effect @p intensity of the style. */ void setEffectIntensity( double intensity ); /** * Returns the effect intensity of the style. */ double effectIntensity() const; private: class Private; Private* const d; }; /** * Returns a reference to the style object of the annotation. */ Style & style(); /** * Returns a const reference to the style object of the annotation. */ const Style & style() const; /** * The Window class contains all information about the popup window * of the annotation that is used to edit the content and properties. */ class OKULARCORE_EXPORT Window { public: /** * Creates a new window. */ Window(); /** * Destroys the window. */ ~Window(); Window( const Window &other ); Window& operator=( const Window &other ); /** * Sets the @p flags of the window. */ void setFlags( int flags ); /** * Returns the flags of the window. */ int flags() const; /** * Sets the top-left @p point of the window. */ void setTopLeft( const NormalizedPoint &point ); /** * Returns the top-left point of the window. */ NormalizedPoint topLeft() const; /** * Sets the @p width of the window. */ void setWidth( int width ); /** * Returns the width of the window. */ int width() const; /** * Sets the @p height of the window. */ void setHeight( int height ); /** * Returns the height of the window. */ int height() const; /** * Sets the @p title of the window. */ void setTitle( const QString &title ); /** * Returns the title of the window. */ QString title() const; /** * Sets the @p summary of the window. */ void setSummary( const QString &summary ); /** * Returns the summary of the window. */ QString summary() const; private: class Private; Private* const d; }; /** * Returns a reference to the window object of the annotation. */ Window & window(); /** * Returns a const reference to the window object of the annotation. */ const Window & window() const; /** * The Revision class contains all information about the revision * of the annotation. */ class Revision { public: /** * Creates a new revision. */ Revision(); /** * Destroys the revision. */ ~Revision(); Revision( const Revision &other ); Revision& operator=( const Revision &other ); /** * Sets the @p annotation the revision belongs to. */ void setAnnotation( Annotation *annotation ); /** * Returns the annotation the revision belongs to. */ Annotation *annotation() const; /** * Sets the @p scope of the revision. * @see RevisionScope */ void setScope( RevisionScope scope ); /** * Returns the scope of the revision. */ RevisionScope scope() const; /** * Sets the @p type of the revision. * @see RevisionType */ void setType( RevisionType type ); /** * Returns the type of the revision. */ RevisionType type() const; private: class Private; Private* const d; }; /** * Returns a reference to the revision list of the annotation. */ QLinkedList< Revision > & revisions(); /** * Returns a reference to the revision list of the annotation. */ const QLinkedList< Revision > & revisions() const; /** * Sets the "native" @p id of the annotation. * * This is for use of the Generator, that can optionally store an * handle (a pointer, an identifier, etc) of the "native" annotation * object, if any. * * @note Okular makes no use of this * * @since 0.7 (KDE 4.1) */ void setNativeId( const QVariant &id ); /** * Returns the "native" id of the annotation. * * @since 0.7 (KDE 4.1) */ QVariant nativeId() const; /** * Sets a function to be called when the annotation is destroyed. * * @warning the function must *not* call any virtual function, * nor subcast. * * @since 0.7 (KDE 4.1) */ void setDisposeDataFunction( DisposeDataFunction func ); /** * Returns whether the annotation can be moved. * * @since 0.7 (KDE 4.1) */ bool canBeMoved() const; /** * Returns whether the annotation can be resized. */ bool canBeResized() const; /** * Returns whether the annotation dialog should be open after creation of the annotation or not * * @since 0.13 (KDE 4.7) */ bool openDialogAfterCreation() const; /** * Returns the sub type of the annotation. */ virtual SubType subType() const = 0; /** * Stores the annotation as xml in @p document under the given parent @p node. */ virtual void store( QDomNode & node, QDomDocument & document ) const; /** * Retrieve the QDomNode representing this annotation's properties * @since 0.17 (KDE 4.11) */ QDomNode getAnnotationPropertiesDomNode() const; /** * Sets annotations internal properties according to the contents of @p node * * @since 0.17 (KDE 4.11) */ void setAnnotationProperties( const QDomNode & node ); protected: /// @cond PRIVATE Annotation( AnnotationPrivate &dd ); Annotation( AnnotationPrivate &dd, const QDomNode &description ); Q_DECLARE_PRIVATE( Annotation ) AnnotationPrivate *d_ptr; /// @endcond private: 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 OKULARCORE_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 OKULARCORE_EXPORT TextAnnotation : public Annotation { public: /** * Describes the type of the text. */ enum TextType { Linked, ///< The annotation is linked to a text InPlace ///< The annotation is located next to the text }; /** * Describes the style of the text. */ enum InplaceIntent { Unknown, ///< Unknown style Callout, ///< Callout style TypeWriter ///< Type writer style }; /** * Creates a new text annotation. */ TextAnnotation(); /** * Creates a new text annotation from the xml @p description */ TextAnnotation( const QDomNode &description ); /** * Destroys the text annotation. */ ~TextAnnotation(); /** * Sets the text @p type of the text annotation. * @see TextType */ void setTextType( TextType type ); /** * Returns the text type of the text annotation. */ TextType textType() const; /** * Sets the @p icon of the text annotation. */ void setTextIcon( const QString &icon ); /** * Returns the icon of the text annotation. */ QString textIcon() const; /** * Sets the @p font of the text annotation. */ void setTextFont( const QFont &font ); /** * Returns the font of the text annotation. */ QFont textFont() const; /** * Sets the inplace @p alignment of the text annotation. */ void setInplaceAlignment( int alignment ); /** * Returns the inplace alignment of the text annotation. */ int inplaceAlignment() const; /** * Sets the inplace callout @p point at @p index. * * @p index must be between 0 and 2. */ void setInplaceCallout( const NormalizedPoint &point, int index ); /** * Returns the inplace callout point for @p index. * * @p index must be between 0 and 2. */ NormalizedPoint inplaceCallout( int index ) const; /** * Returns the transformed (e.g. rotated) inplace callout point for @p index. * * @p index must be between 0 and 2. */ NormalizedPoint transformedInplaceCallout( int index ) const; /** * Returns the inplace @p intent of the text annotation. * @see InplaceIntent */ void setInplaceIntent( InplaceIntent intent ); /** * Returns the inplace intent of the text annotation. */ InplaceIntent inplaceIntent() const; /** * Returns the sub type of the text annotation. */ SubType subType() const override; /** * Stores the text annotation as xml in @p document under the given parent @p node. */ void store( QDomNode &node, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( TextAnnotation ) Q_DISABLE_COPY( TextAnnotation ) }; class OKULARCORE_EXPORT LineAnnotation : public Annotation { public: /** * Describes the line ending style. */ enum TermStyle { Square, ///< Using a square Circle, ///< Using a circle Diamond, ///< Using a diamond OpenArrow, ///< Using an open arrow ClosedArrow, ///< Using a closed arrow None, ///< No special ending style Butt, ///< Using a butt ending ROpenArrow, ///< Using an arrow opened at the right side RClosedArrow, ///< Using an arrow closed at the right side Slash ///< Using a slash }; /** * Describes the line intent. */ enum LineIntent { Unknown, ///< Unknown intent Arrow, ///< Arrow intent Dimension, ///< Dimension intent PolygonCloud ///< Polygon cloud intent }; /** * Creates a new line annotation. */ LineAnnotation(); /** * Creates a new line annotation from the xml @p description */ explicit LineAnnotation( const QDomNode &description ); /** * Destroys the line annotation. */ ~LineAnnotation(); /** * Sets the normalized line @p points of the line annotation. */ void setLinePoints( const QLinkedList &points ); /** * Returns the normalized line points of the line annotation. */ QLinkedList linePoints() const; /** * Returns the transformed (e.g. rotated) normalized line points * of the line annotation. */ QLinkedList transformedLinePoints() const; /** * Sets the line starting @p style of the line annotation. * @see TermStyle */ void setLineStartStyle( TermStyle style ); /** * Returns the line starting style of the line annotation. */ TermStyle lineStartStyle() const; /** * Sets the line ending @p style of the line annotation. * @see TermStyle */ void setLineEndStyle( TermStyle style ); /** * Returns the line ending style of the line annotation. */ TermStyle lineEndStyle() const; /** * Sets whether the line shall be @p closed. */ void setLineClosed( bool closed ); /** * Returns whether the line shall be closed. */ bool lineClosed() const; /** * Sets the inner line @p color of the line annotation. */ void setLineInnerColor( const QColor &color ); /** * Returns the inner line color of the line annotation. */ QColor lineInnerColor() const; /** * Sets the leading forward @p point of the line annotation. */ void setLineLeadingForwardPoint( double point ); /** * Returns the leading forward point of the line annotation. */ double lineLeadingForwardPoint() const; /** * Sets the leading backward @p point of the line annotation. */ void setLineLeadingBackwardPoint( double point ); /** * Returns the leading backward point of the line annotation. */ double lineLeadingBackwardPoint() const; /** * Sets whether the caption shall be @p shown. */ void setShowCaption( bool shown ); /** * Returns whether the caption shall be shown. */ bool showCaption() const; /** * Sets the line @p intent of the line annotation. * @see LineIntent */ void setLineIntent( LineIntent intent ); /** * Returns the line intent of the line annotation. */ LineIntent lineIntent() const; /** * Returns the sub type of the line annotation. */ SubType subType() const override; /** * Stores the line annotation as xml in @p document under the given parent @p node. */ void store( QDomNode &node, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( LineAnnotation ) Q_DISABLE_COPY( LineAnnotation ) }; class OKULARCORE_EXPORT GeomAnnotation : public Annotation { public: // common enums enum GeomType { InscribedSquare, ///< Draw a square InscribedCircle ///< Draw a circle }; /** * Creates a new geometrical annotation. */ GeomAnnotation(); /** * Creates a new geometrical annotation from the xml @p description */ GeomAnnotation( const QDomNode &description ); /** * Destroys the geometrical annotation. */ ~GeomAnnotation(); /** * Sets the geometrical @p type of the geometrical annotation. * @see GeomType */ void setGeometricalType( GeomType type ); /** * Returns the geometrical type of the geometrical annotation. */ GeomType geometricalType() const; /** * Sets the inner @p color of the geometrical annotation. */ void setGeometricalInnerColor( const QColor &color ); /** * Returns the inner color of the geometrical annotation. */ QColor geometricalInnerColor() const; /** * Returns the sub type of the geometrical annotation. */ SubType subType() const override; /** * Stores the geometrical annotation as xml in @p document * under the given parent @p node. */ void store( QDomNode &node, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( GeomAnnotation ) Q_DISABLE_COPY( GeomAnnotation ) }; class OKULARCORE_EXPORT HighlightAnnotation : public Annotation { public: /** * Describes the highlighting style of the annotation. */ enum HighlightType { Highlight, ///< Highlights the text Squiggly, ///< Squiggles the text Underline, ///< Underlines the text StrikeOut ///< Strikes out the text }; /** * Creates a new highlight annotation. */ HighlightAnnotation(); /** * Creates a new highlight annotation from the xml @p description */ explicit HighlightAnnotation( const QDomNode &description ); /** * Destroys the highlight annotation. */ ~HighlightAnnotation(); /** * Sets the @p type of the highlight annotation. * @see HighlightType */ void setHighlightType( HighlightType type ); /** * Returns the type of the highlight annotation. */ HighlightType highlightType() const; /** * The Quad class contains 8 coordinates and style definitions * which describe a line part of the whole highlight annotation. */ class OKULARCORE_EXPORT Quad { public: /** * Creates a new quad. */ Quad(); /** * Destroys the quad. */ ~Quad(); Quad( const Quad &other ); Quad& operator=( const Quad &other ); /** * Sets the normalized @p point at @p index. * * @p index must be between 0 and 3. */ void setPoint( const NormalizedPoint &point, int index ); /** * Returns the normalized point at @p index. * * @p index must be between 0 and 3. */ NormalizedPoint point( int index ) const; /** * Returns the transformed (e.g. rotated) normalized point at @p index. * * @p index must be between 0 and 3. */ NormalizedPoint transformedPoint( int index ) const; /** * Sets whether a cap should be used at the start. */ void setCapStart( bool value ); /** * Returns whether a cap should be used at the start. */ bool capStart() const; /** * Sets whether a cap should be used at the end. */ void setCapEnd( bool value ); /** * Returns whether a cap should be used at the end. */ bool capEnd() const; /** * Sets the @p width of the drawing feather. */ void setFeather( double width ); /** * Returns the width of the drawing feather. */ double feather() const; /** * Transforms the quad coordinates with the transformation defined * by @p matrix. */ void transform( const QTransform &matrix ); private: class Private; Private* const d; }; /** * Returns a reference to the quad list of the highlight annotation. */ QList< Quad > & highlightQuads(); /** * Returns the sub type of the highlight annotation. */ SubType subType() const override; /** * Stores the highlight annotation as xml in @p document * under the given parent @p node. */ void store( QDomNode &node, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( HighlightAnnotation ) Q_DISABLE_COPY( HighlightAnnotation ) }; class OKULARCORE_EXPORT StampAnnotation : public Annotation { public: /** * Creates a new stamp annotation. */ StampAnnotation(); /** * Creates a new stamp annotation from the xml @p description */ explicit StampAnnotation( const QDomNode &description ); /** * Destroys the stamp annotation. */ ~StampAnnotation(); /** * Sets the @p name of the icon for the stamp annotation. */ void setStampIconName( const QString &name ); /** * Returns the name of the icon. */ QString stampIconName() const; /** * Returns the sub type of the stamp annotation. */ SubType subType() const override; /** * Stores the stamp annotation as xml in @p document * under the given parent @p node. */ void store( QDomNode &node, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( StampAnnotation ) Q_DISABLE_COPY( StampAnnotation ) }; class OKULARCORE_EXPORT InkAnnotation : public Annotation { public: /** * Creates a new ink annotation. */ InkAnnotation(); /** * Creates a new ink annotation from the xml @p description */ InkAnnotation( const QDomNode &description ); /** * Destroys the ink annotation. */ ~InkAnnotation(); /** * Sets the @p paths of points for the ink annotation. */ void setInkPaths( const QList< QLinkedList > &paths ); /** * Returns the paths of points of the ink annotation. */ QList< QLinkedList > inkPaths() const; /** * Returns the paths of transformed (e.g. rotated) points of * the ink annotation. */ QList< QLinkedList > transformedInkPaths() const; /** * Returns the sub type of the ink annotation. */ SubType subType() const override; /** * Stores the ink annotation as xml in @p document * under the given parent @p node. */ void store( QDomNode &node, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( InkAnnotation ) Q_DISABLE_COPY( InkAnnotation ) }; class OKULARCORE_EXPORT CaretAnnotation : public Annotation { public: /** * Describes the highlighting style of the annotation. */ enum CaretSymbol { None, ///< No symbol to be associated with the text P ///< A 'paragraph' symbol }; /** * Creates a new caret annotation. */ CaretAnnotation(); /** * Creates a new caret annotation from the xml @p description */ explicit CaretAnnotation( const QDomNode &description ); /** * Destroys the caret annotation. */ ~CaretAnnotation(); /** * Sets the @p symbol for the caret annotation. */ void setCaretSymbol( CaretAnnotation::CaretSymbol symbol ); /** * Returns the symbol of the annotation. */ CaretAnnotation::CaretSymbol caretSymbol() const; /** * Returns the sub type of the caret annotation. */ SubType subType() const override; /** * Stores the caret annotation as xml in @p document * under the given parent @p node. */ void store( QDomNode &node, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( CaretAnnotation ) Q_DISABLE_COPY( CaretAnnotation ) }; class OKULARCORE_EXPORT FileAttachmentAnnotation : public Annotation { public: /** * Creates a new file attachment annotation. */ FileAttachmentAnnotation(); /** * Creates a new file attachment annotation from the xml @p description */ explicit FileAttachmentAnnotation( const QDomNode &description ); /** * Destroys the file attachment annotation. */ virtual ~FileAttachmentAnnotation(); /** * Gets the name of the icon. */ QString fileIconName() const; /** * Sets the @p name of the icon for the file attachment annotation. */ void setFileIconName( const QString &name ); /** * Gets the embedded file object. */ EmbeddedFile* embeddedFile() const; /** * Sets the @p object representing the embedded file of the file * attachment annotation. */ void setEmbeddedFile( EmbeddedFile *object ); /** * Returns the sub type of the file attachment annotation. */ SubType subType() const override; /** * Stores the file attachment annotation as xml in @p document * under the given parent @p node. */ void store( QDomNode &node, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( FileAttachmentAnnotation ) Q_DISABLE_COPY( FileAttachmentAnnotation ) }; /** * \short Sound annotation. * * The sound annotation represents a sound to be played when activated. * * @since 0.7 (KDE 4.1) */ class OKULARCORE_EXPORT SoundAnnotation : public Annotation { public: /** * Creates a new sound annotation. */ SoundAnnotation(); /** * Creates a new sound annotation from the xml @p description */ SoundAnnotation( const QDomNode &description ); /** * Destroys the sound annotation. */ virtual ~SoundAnnotation(); /** * Gets the name of the icon. */ QString soundIconName() const; /** * Sets the @p name of the icon for the sound annotation. */ void setSoundIconName( const QString &name ); /** * Gets the sound object. */ Sound* sound() const; /** * Sets the @p object representing the sound of the file * attachment annotation. */ void setSound( Sound *object ); /** * Returns the sub type of the sound annotation. */ SubType subType() const override; /** * Stores the sound annotation as xml in @p document * under the given parent @p node. */ void store( QDomNode &node, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( SoundAnnotation ) Q_DISABLE_COPY( SoundAnnotation ) }; /** * \short Movie annotation. * * The movie annotation represents a movie to be played when activated. * * @since 0.8 (KDE 4.2) */ class OKULARCORE_EXPORT MovieAnnotation : public Annotation { public: /** * Creates a new movie annotation. */ MovieAnnotation(); /** * Creates a new movie annotation from the xml @p description */ MovieAnnotation( const QDomNode &description ); /** * Destroys the movie annotation. */ virtual ~MovieAnnotation(); /** * Gets the movie object. */ Movie* movie() const; /** * Sets the new @p movie object. */ void setMovie( Movie *movie ); /** * Returns the sub type of the movie annotation. */ SubType subType() const override; /** * Stores the movie annotation as xml in @p document * under the given @p parentNode. */ void store( QDomNode &parentNode, QDomDocument &document ) const override; private: Q_DECLARE_PRIVATE( MovieAnnotation ) Q_DISABLE_COPY( MovieAnnotation ) }; /** * \short Screen annotation. * * The screen annotation specifies a region of a page upon which media clips * may be played. It also serves as an object from which actions can be triggered. * * @since 0.16 (KDE 4.10) */ class OKULARCORE_EXPORT ScreenAnnotation : public Annotation { public: /** * Creates a new screen annotation. */ ScreenAnnotation(); /** * Creates a new screen annotation from the xml @p description */ ScreenAnnotation( const QDomNode &description ); /** * Destroys the screen annotation. */ virtual ~ScreenAnnotation(); /** * Returns the sub type of the screen annotation. */ SubType subType() const override; /** * Stores the screen annotation as xml in @p document * under the given @p parentNode. */ void store( QDomNode &parentNode, QDomDocument &document ) const override; /** * Sets the @p action that is executed when the annotation is triggered. * * @since 0.16 (KDE 4.10) */ void setAction( Action *action ); /** * Returns the action that is executed when the annotation is triggered or @c 0 if not action has been defined. * * @since 0.16 (KDE 4.10) */ Action* action() const; /** * Sets the additional @p action of the given @p type. * * @since 0.16 (KDE 4.10) */ void setAdditionalAction( AdditionalActionType type, Action *action ); /** * Returns the additional action of the given @p type or @c 0 if no action has been defined. * * @since 0.16 (KDE 4.10) */ Action* additionalAction( AdditionalActionType type ) const; private: Q_DECLARE_PRIVATE( ScreenAnnotation ) Q_DISABLE_COPY( ScreenAnnotation ) }; /** * \short Widget annotation. * * The widget annotation represents a widget on a page. * * @since 0.16 (KDE 4.10) */ class OKULARCORE_EXPORT WidgetAnnotation : public Annotation { public: /** * Creates a new widget annotation. */ WidgetAnnotation(); /** * Creates a new widget annotation from the xml @p description */ WidgetAnnotation( const QDomNode &description ); /** * Destroys the widget annotation. */ virtual ~WidgetAnnotation(); /** * Returns the sub type of the widget annotation. */ SubType subType() const override; /** * Stores the widget annotation as xml in @p document * under the given @p parentNode. */ void store( QDomNode &parentNode, QDomDocument &document ) const override; /** * Sets the additional @p action of the given @p type. * * @since 0.16 (KDE 4.10) */ void setAdditionalAction( AdditionalActionType type, Action *action ); /** * Returns the additional action of the given @p type or @c 0 if no action has been defined. * * @since 0.16 (KDE 4.10) */ Action* additionalAction( AdditionalActionType type ) const; private: Q_DECLARE_PRIVATE( WidgetAnnotation ) Q_DISABLE_COPY( WidgetAnnotation ) }; /** * \short RichMedia annotation. * * The rich media annotation represents an video or sound on a page. * * @since 1.0 */ class OKULARCORE_EXPORT RichMediaAnnotation : public Annotation { public: /** * Creates a new rich media annotation. */ RichMediaAnnotation(); /** * Creates a new rich media annotation from the xml @p description */ RichMediaAnnotation( const QDomNode &description ); /** * Destroys the rich media annotation. */ virtual ~RichMediaAnnotation(); /** * Returns the sub type of the rich media annotation. */ SubType subType() const override; /** * Stores the rich media annotation as xml in @p document * under the given @p parentNode. */ void store( QDomNode &parentNode, QDomDocument &document ) const override; /** * Gets the movie object. */ Movie* movie() const; /** * Sets the new @p movie object. */ void setMovie( Movie *movie ); /** * Sets the @p object representing the embedded file. */ void setEmbeddedFile( EmbeddedFile *object ); /** * Gets the embedded file object. */ EmbeddedFile* embeddedFile() const; private: Q_DECLARE_PRIVATE( RichMediaAnnotation ) Q_DISABLE_COPY( RichMediaAnnotation ) }; } #endif diff --git a/core/form.cpp b/core/form.cpp index 45c3b37cd..2071da0f2 100644 --- a/core/form.cpp +++ b/core/form.cpp @@ -1,281 +1,296 @@ /*************************************************************************** * Copyright (C) 2007 by Pino Toscano * * * * 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. * ***************************************************************************/ #include "form.h" #include "form_p.h" // qt includes #include #include "action.h" using namespace Okular; FormFieldPrivate::FormFieldPrivate( FormField::FieldType type ) : m_type( type ), m_activateAction( nullptr ) { } FormFieldPrivate::~FormFieldPrivate() { delete m_activateAction; + qDeleteAll( m_additionalActions.values() ); + qDeleteAll( m_additionalAnnotActions.values() ); } void FormFieldPrivate::setDefault() { m_default = value(); } FormField::FormField( FormFieldPrivate &dd ) : d_ptr( &dd ) { d_ptr->q_ptr = this; } FormField::~FormField() { delete d_ptr; } FormField::FieldType FormField::type() const { Q_D( const FormField ); return d->m_type; } bool FormField::isReadOnly() const { return false; } void FormField::setReadOnly( bool ) { } bool FormField::isVisible() const { return true; } void FormField::setVisible( bool ) { } Action* FormField::activationAction() const { Q_D( const FormField ); return d->m_activateAction; } void FormField::setActivationAction( Action *action ) { Q_D( FormField ); delete d->m_activateAction; d->m_activateAction = action; } Action* FormField::additionalAction( AdditionalActionType type ) const { Q_D( const FormField ); return d->m_additionalActions.value(type); } void FormField::setAdditionalAction( AdditionalActionType type, Action *action ) { Q_D( FormField ); delete d->m_additionalActions.value(type); d->m_additionalActions[type] = action; } +Action* FormField::additionalAction( Annotation::AdditionalActionType type ) const +{ + Q_D( const FormField ); + return d->m_additionalAnnotActions.value(type); +} + +void FormField::setAdditionalAction( Annotation::AdditionalActionType type, Action *action ) +{ + Q_D( FormField ); + delete d->m_additionalAnnotActions.value(type); + d->m_additionalAnnotActions[type] = action; +} + class Okular::FormFieldButtonPrivate : public Okular::FormFieldPrivate { public: FormFieldButtonPrivate() : FormFieldPrivate( FormField::FormButton ) { } Q_DECLARE_PUBLIC( FormFieldButton ) void setValue( const QString& v ) override { Q_Q( FormFieldButton ); q->setState( QVariant( v ).toBool() ); } QString value() const override { Q_Q( const FormFieldButton ); return qVariantFromValue( q->state() ).toString(); } }; FormFieldButton::FormFieldButton() : FormField( *new FormFieldButtonPrivate() ) { } FormFieldButton::~FormFieldButton() { } void FormFieldButton::setState( bool ) { } class Okular::FormFieldTextPrivate : public Okular::FormFieldPrivate { public: FormFieldTextPrivate() : FormFieldPrivate( FormField::FormText ) { } Q_DECLARE_PUBLIC( FormFieldText ) void setValue( const QString& v ) override { Q_Q( FormFieldText ); q->setText( v ); } QString value() const override { Q_Q( const FormFieldText ); return q->text(); } }; FormFieldText::FormFieldText() : FormField( *new FormFieldTextPrivate() ) { } FormFieldText::~FormFieldText() { } void FormFieldText::setText( const QString& ) { } bool FormFieldText::isPassword() const { return false; } bool FormFieldText::isRichText() const { return false; } int FormFieldText::maximumLength() const { return -1; } Qt::Alignment FormFieldText::textAlignment() const { return Qt::AlignVCenter | Qt::AlignLeft; } bool FormFieldText::canBeSpellChecked() const { return false; } class Okular::FormFieldChoicePrivate : public Okular::FormFieldPrivate { public: FormFieldChoicePrivate() : FormFieldPrivate( FormField::FormChoice ) { } Q_DECLARE_PUBLIC( FormFieldChoice ) void setValue( const QString& v ) override { Q_Q( FormFieldChoice ); QStringList choices = v.split( QLatin1Char (';'), QString::SkipEmptyParts ); QList newchoices; foreach ( const QString& str, choices ) { bool ok = true; int val = str.toInt( &ok ); if ( ok ) newchoices.append( val ); } if ( !newchoices.isEmpty() ) q->setCurrentChoices( newchoices ); } QString value() const override { Q_Q( const FormFieldChoice ); QList choices = q->currentChoices(); qSort( choices ); QStringList list; foreach ( int c, choices ) { list.append( QString::number( c ) ); } return list.join( QStringLiteral( ";" ) ); } }; FormFieldChoice::FormFieldChoice() : FormField( *new FormFieldChoicePrivate() ) { } FormFieldChoice::~FormFieldChoice() { } bool FormFieldChoice::isEditable() const { return false; } bool FormFieldChoice::multiSelect() const { return false; } void FormFieldChoice::setCurrentChoices( const QList< int >& ) { } QString FormFieldChoice::editChoice() const { return QString(); } void FormFieldChoice::setEditChoice( const QString& ) { } Qt::Alignment FormFieldChoice::textAlignment() const { return Qt::AlignVCenter | Qt::AlignLeft; } bool FormFieldChoice::canBeSpellChecked() const { return false; } diff --git a/core/form.h b/core/form.h index 691215810..bcc41de43 100644 --- a/core/form.h +++ b/core/form.h @@ -1,382 +1,392 @@ /*************************************************************************** * Copyright (C) 2007 by Pino Toscano * * * * 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_FORM_H_ #define _OKULAR_FORM_H_ #include "okularcore_export.h" #include "area.h" +#include "annotations.h" #include namespace Okular { class Action; class Page; class PagePrivate; class FormFieldPrivate; class FormFieldButtonPrivate; class FormFieldTextPrivate; class FormFieldChoicePrivate; /** * @short The base interface of a form field. * * This is the very basic interface to represent a field in a form. * * This is not meant to be used as a direct base for the form fields in a * document, but its abstract subclasses are. */ class OKULARCORE_EXPORT FormField { /// @cond PRIVATE friend class Page; friend class PagePrivate; /// @endcond public: /** * The types of form field. */ enum FieldType { FormButton, ///< A "button". See @ref FormFieldButton::ButtonType. FormText, ///< A field of variable text. See @ref FormFieldText::TextType. FormChoice, ///< A choice field. See @ref FormFieldChoice::ChoiceType. FormSignature ///< A signature. }; virtual ~FormField(); /** * The type of the field. */ FieldType type() const; /** * The bouding rect of the field, in normalized coordinates. */ virtual NormalizedRect rect() const = 0; /** * The ID of the field. */ virtual int id() const = 0; /** * The internal name of the field, to be used when referring to the * field in eg scripts. */ virtual QString name() const = 0; /** * The visible name of the field, to be used in the user interface * (eg in error messages, etc). */ virtual QString uiName() const = 0; /** * Whether the field is read-only. */ virtual bool isReadOnly() const; /** * Whether the field is read-only. * * @since 1.4 */ virtual void setReadOnly( bool value ); /** * Whether this form field is visible. */ virtual bool isVisible() const; /** * Whether the field is visible. * * @since 1.5 */ virtual void setVisible( bool value ); Action* activationAction() const; /** * Describes the type of form additional action. * * @since 1.1 */ enum AdditionalActionType { FieldModified, ///< An action to be performed when the user modifies the field FormatField, ///< An action to be performed before the field is formatted to display its value ValidateField, ///< An action to be performed when the field value changes CalculateField, ///< An action to be performed when the field needs to be recalculated }; /** * Returns the additional action of the given @p type or @c nullptr if no action has been defined. * * @since 1.1 */ Action* additionalAction( AdditionalActionType type ) const; + /* Returns the additional action of the given @p type or @c nullptr if no action has been defined. + * + * This is for actions of annotation widgets associated with the FormField + * + * @since 1.5 + */ + Action* additionalAction( Annotation::AdditionalActionType type ) const; + protected: /// @cond PRIVATE FormField( FormFieldPrivate &dd ); Q_DECLARE_PRIVATE( FormField ) FormFieldPrivate *d_ptr; /// @endcond void setActivationAction( Action *action ); void setAdditionalAction( AdditionalActionType type, Action *action ); + void setAdditionalAction( Annotation::AdditionalActionType type, Action *action ); private: Q_DISABLE_COPY( FormField ) }; /** * @short Interface of a button form field. * * This is the base interface to reimplement to represent a button field, like * a push button, a check box or a radio button. * * @since 0.7 (KDE 4.1) */ class OKULARCORE_EXPORT FormFieldButton : public FormField { public: /** * The types of button field. */ enum ButtonType { Push, ///< A simple push button. CheckBox, ///< A check box. Radio ///< A radio button. }; virtual ~FormFieldButton(); /** The particular type of the button field. */ virtual ButtonType buttonType() const = 0; /** * The caption to be used for the button. */ virtual QString caption() const = 0; /** * The state of the button. */ virtual bool state() const = 0; /** * Sets the state of the button to the new \p state . */ virtual void setState( bool state ); /** * The list with the IDs of siblings (ie, buttons belonging to the same * group as the current one. * * Valid only for \ref Radio buttons, an empty list otherwise. */ virtual QList< int > siblings() const = 0; protected: FormFieldButton(); private: Q_DECLARE_PRIVATE( FormFieldButton ) Q_DISABLE_COPY( FormFieldButton ) }; /** * @short Interface of a text form field. * * This is the base interface to reimplement to represent a text field, ie a * field where the user insert text. */ class OKULARCORE_EXPORT FormFieldText : public FormField { public: /** * The types of text field. */ enum TextType { Normal, ///< A simple singleline text field. Multiline, ///< A multiline text field. FileSelect ///< An input field to select the path of a file on disk. }; virtual ~FormFieldText(); /** * The particular type of the text field. */ virtual TextType textType() const = 0; /** * The text of text field. */ virtual QString text() const = 0; /** * Sets the new @p text in the text field. * * The default implementation does nothing. * * Reimplemented only if the setting of new text is supported. */ virtual void setText( const QString& text ); /** * Whether this text field is a password input, eg its text @b must be * replaced with asterisks. * * Always false for @ref FileSelect text fields. */ virtual bool isPassword() const; /** * Whether this text field should allow rich text. */ virtual bool isRichText() const; /** * The maximum length allowed for the text of text field, or -1 if * there is no limitation for the text. */ virtual int maximumLength() const; /** * The alignment of the text within the field. */ virtual Qt::Alignment textAlignment() const; /** * Whether the text inserted manually in the field (where possible) * can be spell-checked. * * @note meaningful only if the field is editable. */ virtual bool canBeSpellChecked() const; protected: FormFieldText(); private: Q_DECLARE_PRIVATE( FormFieldText ) Q_DISABLE_COPY( FormFieldText ) }; /** * @short Interface of a choice form field. * * This is the base interface to reimplement to represent a choice field, ie a * field where the user can select one (of more) element(s) among a set of * choices. */ class OKULARCORE_EXPORT FormFieldChoice : public FormField { public: /** * The types of choice field. */ enum ChoiceType { ComboBox, ///< A combo box choice field. ListBox ///< A list box choice field. }; virtual ~FormFieldChoice(); /** * The particular type of the choice field. */ virtual ChoiceType choiceType() const = 0; /** * The possible choices of the choice field. */ virtual QStringList choices() const = 0; /** * Whether this ComboBox is editable, ie the user can type in a custom * value. * * Always false for the other types of choices. */ virtual bool isEditable() const; /** * Whether more than one choice of this ListBox can be selected at the * same time. * * Always false for the other types of choices. */ virtual bool multiSelect() const; /** * The currently selected choices. * * Always one element in the list in case of single choice elements. */ virtual QList< int > currentChoices() const = 0; /** * Sets the selected choices to @p choices . */ virtual void setCurrentChoices( const QList< int >& choices ); /** The text entered into an editable combo box choice field @since 0.16 (KDE 4.10) */ virtual QString editChoice() const; /** Sets the text entered into an editable combo box choice field @since 0.16 (KDE 4.10) */ virtual void setEditChoice( const QString& text ); /** * The alignment of the text within the field. */ virtual Qt::Alignment textAlignment() const; /** * Whether the text inserted manually in the field (where possible) * can be spell-checked. * * @note meaningful only if the field is editable. */ virtual bool canBeSpellChecked() const; protected: FormFieldChoice(); private: Q_DECLARE_PRIVATE( FormFieldChoice ) Q_DISABLE_COPY( FormFieldChoice ) }; } #endif diff --git a/core/form_p.h b/core/form_p.h index c4347b980..ff4e1211e 100644 --- a/core/form_p.h +++ b/core/form_p.h @@ -1,44 +1,45 @@ /*************************************************************************** * Copyright (C) 2007 by Pino Toscano * * * * 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_FORM_P_H #define OKULAR_FORM_P_H #include "form.h" #include namespace Okular { class Action; class FormField; class FormFieldPrivate { public: FormFieldPrivate( FormField::FieldType type ); virtual ~FormFieldPrivate(); void setDefault(); virtual void setValue( const QString& ) = 0; virtual QString value() const = 0; FormField::FieldType m_type; QString m_default; Action *m_activateAction; QHash m_additionalActions; + QHash m_additionalAnnotActions; Q_DECLARE_PUBLIC( FormField ) FormField *q_ptr; }; } #endif diff --git a/generators/poppler/CMakeLists.txt b/generators/poppler/CMakeLists.txt index d13d697d4..025518c41 100644 --- a/generators/poppler/CMakeLists.txt +++ b/generators/poppler/CMakeLists.txt @@ -1,119 +1,129 @@ remove_definitions(-DTRANSLATION_DOMAIN="okular") add_definitions(-DTRANSLATION_DOMAIN="okular_poppler") add_subdirectory( conf ) if (Poppler_VERSION VERSION_GREATER "0.23.99") set (HAVE_POPPLER_0_24 1) endif() if (Poppler_VERSION VERSION_GREATER "0.27.99") set (HAVE_POPPLER_0_28 1) endif() if (Poppler_VERSION VERSION_GREATER "0.35.99") set (HAVE_POPPLER_0_36 1) endif() if (Poppler_VERSION VERSION_GREATER "0.36.99") set (HAVE_POPPLER_0_37 1) endif() set(CMAKE_REQUIRED_LIBRARIES Poppler::Qt5 Qt5::Core Qt5::Gui) check_cxx_source_compiles(" #include int main() { Poppler::LinkOCGState *l = 0; return 0; } " HAVE_POPPLER_0_50) check_cxx_source_compiles(" #include #include int main() { Poppler::FormFieldButton *ff = 0; Poppler::Link *l = ff->additionalAction(Poppler::FormField::CalculateField); return 0; } " HAVE_POPPLER_0_53) check_cxx_source_compiles(" #include int main() { Poppler::Document::RenderHint hint = Poppler::Document::HideAnnotations; return 0; } " HAVE_POPPLER_0_60) check_cxx_source_compiles(" #include #include int main() { Poppler::Page *p; p->renderToImage(0, 0, 0, 0, 0, 0, Poppler::Page::Rotate0, nullptr, nullptr, QVariant()); return 0; } " HAVE_POPPLER_0_62) check_cxx_source_compiles(" #include #include int main() { Poppler::Page *p; p->renderToImage(0, 0, 0, 0, 0, 0, Poppler::Page::Rotate0, nullptr, nullptr, nullptr, QVariant()); return 0; } " HAVE_POPPLER_0_63) check_cxx_source_compiles(" #include #include #include int main() { Poppler::FormField *f; f->setReadOnly(true); f->setVisible(true); Poppler::Link *l; l->nextLinks(); } " HAVE_POPPLER_0_64) +check_cxx_source_compiles(" +#include +#include +int main() +{ + Poppler::FormField *f; + f->additionalAction(Poppler::Annotation::CursorEnteringAction); +} +" HAVE_POPPLER_0_65) + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/config-okular-poppler.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-okular-poppler.h ) include_directories( ${CMAKE_CURRENT_SOURCE_DIR}/../.. ) ########### next target ############### set(okularGenerator_poppler_PART_SRCS generator_pdf.cpp formfields.cpp annots.cpp ) ki18n_wrap_ui(okularGenerator_poppler_PART_SRCS conf/pdfsettingswidget.ui ) kconfig_add_kcfg_files(okularGenerator_poppler_PART_SRCS conf/pdfsettings.kcfgc ) okular_add_generator(okularGenerator_poppler ${okularGenerator_poppler_PART_SRCS}) target_link_libraries(okularGenerator_poppler okularcore KF5::I18n KF5::Completion Poppler::Qt5 Qt5::Xml) ########### install files ############### install( FILES okularPoppler.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) install( PROGRAMS okularApplication_pdf.desktop org.kde.mobile.okular_pdf.desktop DESTINATION ${KDE_INSTALL_APPDIR} ) install( FILES org.kde.okular-poppler.metainfo.xml DESTINATION ${KDE_INSTALL_METAINFODIR} ) diff --git a/generators/poppler/config-okular-poppler.h.cmake b/generators/poppler/config-okular-poppler.h.cmake index 99f23fc86..9fa0def93 100644 --- a/generators/poppler/config-okular-poppler.h.cmake +++ b/generators/poppler/config-okular-poppler.h.cmake @@ -1,29 +1,32 @@ /* Defined if we have the 0.24 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_24 1 /* Defined if we have the 0.28 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_28 1 /* Defined if we have the 0.36 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_36 1 /* Defined if we have the 0.37 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_37 1 /* Defined if we have the 0.50 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_50 1 /* Defined if we have the 0.53 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_53 1 /* Defined if we have the 0.60 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_60 1 /* Defined if we have the 0.62 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_62 1 /* Defined if we have the 0.63 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_63 1 /* Defined if we have the 0.64 version of the Poppler library */ #cmakedefine HAVE_POPPLER_0_64 1 + +/* Defined if we have the 0.65 version of the Poppler library */ +#cmakedefine HAVE_POPPLER_0_65 1 diff --git a/generators/poppler/formfields.cpp b/generators/poppler/formfields.cpp index bb635e814..e2f3dbdf1 100644 --- a/generators/poppler/formfields.cpp +++ b/generators/poppler/formfields.cpp @@ -1,357 +1,370 @@ /*************************************************************************** * Copyright (C) 2007 by Pino Toscano * + * Copyright (C) 2018 by Intevation GmbH * * * * 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. * ***************************************************************************/ #include "formfields.h" #include "core/action.h" #include #include extern Okular::Action* createLinkFromPopplerLink(const Poppler::Link *popplerLink, bool deletePopplerLink = true); +#ifdef HAVE_POPPLER_0_65 +# define SET_ANNOT_ACTIONS \ + setAdditionalAction( Okular::Annotation::CursorEntering, createLinkFromPopplerLink( field->additionalAction( Poppler::Annotation::CursorEnteringAction ) ) ); \ + setAdditionalAction( Okular::Annotation::CursorLeaving, createLinkFromPopplerLink( field->additionalAction( Poppler::Annotation::CursorLeavingAction ) ) ); \ + setAdditionalAction( Okular::Annotation::MousePressed, createLinkFromPopplerLink( field->additionalAction( Poppler::Annotation::MousePressedAction ) ) ); \ + setAdditionalAction( Okular::Annotation::MouseReleased, createLinkFromPopplerLink( field->additionalAction( Poppler::Annotation::MouseReleasedAction ) ) ); \ + setAdditionalAction( Okular::Annotation::FocusIn, createLinkFromPopplerLink( field->additionalAction( Poppler::Annotation::FocusInAction ) ) ); \ + setAdditionalAction( Okular::Annotation::FocusOut, createLinkFromPopplerLink( field->additionalAction( Poppler::Annotation::FocusOutAction ) ) ); +#else +# define SET_ANNOT_ACTIONS +#endif #ifdef HAVE_POPPLER_0_53 #define SET_ACTIONS \ setActivationAction( createLinkFromPopplerLink( field->activationAction() ) ); \ setAdditionalAction( Okular::FormField::FieldModified, createLinkFromPopplerLink( field->additionalAction( Poppler::FormField::FieldModified ) ) ); \ setAdditionalAction( Okular::FormField::FormatField, createLinkFromPopplerLink( field->additionalAction( Poppler::FormField::FormatField ) ) ); \ setAdditionalAction( Okular::FormField::ValidateField, createLinkFromPopplerLink( field->additionalAction( Poppler::FormField::ValidateField ) ) ); \ - setAdditionalAction( Okular::FormField::CalculateField, createLinkFromPopplerLink( field->additionalAction( Poppler::FormField::CalculateField ) ) ); + setAdditionalAction( Okular::FormField::CalculateField, createLinkFromPopplerLink( field->additionalAction( Poppler::FormField::CalculateField ) ) ); \ + SET_ANNOT_ACTIONS #else #define SET_ACTIONS \ setActivationAction( createLinkFromPopplerLink( field->activationAction() ) ); #endif PopplerFormFieldButton::PopplerFormFieldButton( Poppler::FormFieldButton * field ) : Okular::FormFieldButton(), m_field( field ) { m_rect = Okular::NormalizedRect::fromQRectF( m_field->rect() ); m_id = m_field->id(); SET_ACTIONS } PopplerFormFieldButton::~PopplerFormFieldButton() { delete m_field; } Okular::NormalizedRect PopplerFormFieldButton::rect() const { return m_rect; } int PopplerFormFieldButton::id() const { return m_id; } QString PopplerFormFieldButton::name() const { return m_field->name(); } QString PopplerFormFieldButton::uiName() const { return m_field->uiName(); } bool PopplerFormFieldButton::isReadOnly() const { return m_field->isReadOnly(); } void PopplerFormFieldButton::setReadOnly( bool value ) { #ifdef HAVE_POPPLER_0_64 m_field->setReadOnly( value ); #else Q_UNUSED( value ); #endif } bool PopplerFormFieldButton::isVisible() const { return m_field->isVisible(); } void PopplerFormFieldButton::setVisible( bool value ) { #ifdef HAVE_POPPLER_0_64 m_field->setVisible( value ); #else Q_UNUSED( value ); #endif } Okular::FormFieldButton::ButtonType PopplerFormFieldButton::buttonType() const { switch ( m_field->buttonType() ) { case Poppler::FormFieldButton::Push: return Okular::FormFieldButton::Push; case Poppler::FormFieldButton::CheckBox: return Okular::FormFieldButton::CheckBox; case Poppler::FormFieldButton::Radio: return Okular::FormFieldButton::Radio; } return Okular::FormFieldButton::Push; } QString PopplerFormFieldButton::caption() const { return m_field->caption(); } bool PopplerFormFieldButton::state() const { return m_field->state(); } void PopplerFormFieldButton::setState( bool state ) { m_field->setState( state ); } QList< int > PopplerFormFieldButton::siblings() const { return m_field->siblings(); } PopplerFormFieldText::PopplerFormFieldText( Poppler::FormFieldText * field ) : Okular::FormFieldText(), m_field( field ) { m_rect = Okular::NormalizedRect::fromQRectF( m_field->rect() ); m_id = m_field->id(); SET_ACTIONS } PopplerFormFieldText::~PopplerFormFieldText() { delete m_field; } Okular::NormalizedRect PopplerFormFieldText::rect() const { return m_rect; } int PopplerFormFieldText::id() const { return m_id; } QString PopplerFormFieldText::name() const { return m_field->name(); } QString PopplerFormFieldText::uiName() const { return m_field->uiName(); } bool PopplerFormFieldText::isReadOnly() const { return m_field->isReadOnly(); } void PopplerFormFieldText::setReadOnly( bool value ) { #ifdef HAVE_POPPLER_0_64 m_field->setReadOnly( value ); #else Q_UNUSED( value ); #endif } bool PopplerFormFieldText::isVisible() const { return m_field->isVisible(); } void PopplerFormFieldText::setVisible( bool value ) { #ifdef HAVE_POPPLER_0_64 m_field->setVisible( value ); #else Q_UNUSED( value ); #endif } Okular::FormFieldText::TextType PopplerFormFieldText::textType() const { switch ( m_field->textType() ) { case Poppler::FormFieldText::Normal: return Okular::FormFieldText::Normal; case Poppler::FormFieldText::Multiline: return Okular::FormFieldText::Multiline; case Poppler::FormFieldText::FileSelect: return Okular::FormFieldText::FileSelect; } return Okular::FormFieldText::Normal; } QString PopplerFormFieldText::text() const { return m_field->text(); } void PopplerFormFieldText::setText( const QString& text ) { m_field->setText( text ); } bool PopplerFormFieldText::isPassword() const { return m_field->isPassword(); } bool PopplerFormFieldText::isRichText() const { return m_field->isRichText(); } int PopplerFormFieldText::maximumLength() const { return m_field->maximumLength(); } Qt::Alignment PopplerFormFieldText::textAlignment() const { return Qt::AlignTop | m_field->textAlignment(); } bool PopplerFormFieldText::canBeSpellChecked() const { return m_field->canBeSpellChecked(); } PopplerFormFieldChoice::PopplerFormFieldChoice( Poppler::FormFieldChoice * field ) : Okular::FormFieldChoice(), m_field( field ) { m_rect = Okular::NormalizedRect::fromQRectF( m_field->rect() ); m_id = m_field->id(); SET_ACTIONS } PopplerFormFieldChoice::~PopplerFormFieldChoice() { delete m_field; } Okular::NormalizedRect PopplerFormFieldChoice::rect() const { return m_rect; } int PopplerFormFieldChoice::id() const { return m_id; } QString PopplerFormFieldChoice::name() const { return m_field->name(); } QString PopplerFormFieldChoice::uiName() const { return m_field->uiName(); } bool PopplerFormFieldChoice::isReadOnly() const { return m_field->isReadOnly(); } void PopplerFormFieldChoice::setReadOnly( bool value ) { #ifdef HAVE_POPPLER_0_64 m_field->setReadOnly( value ); #else Q_UNUSED( value ); #endif } bool PopplerFormFieldChoice::isVisible() const { return m_field->isVisible(); } void PopplerFormFieldChoice::setVisible( bool value ) { #ifdef HAVE_POPPLER_0_64 m_field->setVisible( value ); #else Q_UNUSED( value ); #endif } Okular::FormFieldChoice::ChoiceType PopplerFormFieldChoice::choiceType() const { switch ( m_field->choiceType() ) { case Poppler::FormFieldChoice::ComboBox: return Okular::FormFieldChoice::ComboBox; case Poppler::FormFieldChoice::ListBox: return Okular::FormFieldChoice::ListBox; } return Okular::FormFieldChoice::ListBox; } QStringList PopplerFormFieldChoice::choices() const { return m_field->choices(); } bool PopplerFormFieldChoice::isEditable() const { return m_field->isEditable(); } bool PopplerFormFieldChoice::multiSelect() const { return m_field->multiSelect(); } QList PopplerFormFieldChoice::currentChoices() const { return m_field->currentChoices(); } void PopplerFormFieldChoice::setCurrentChoices( const QList& choices ) { m_field->setCurrentChoices( choices ); } QString PopplerFormFieldChoice::editChoice() const { return m_field->editChoice(); } void PopplerFormFieldChoice::setEditChoice( const QString& text ) { m_field->setEditChoice( text ); } Qt::Alignment PopplerFormFieldChoice::textAlignment() const { return Qt::AlignTop | m_field->textAlignment(); } bool PopplerFormFieldChoice::canBeSpellChecked() const { return m_field->canBeSpellChecked(); } diff --git a/ui/formwidgets.cpp b/ui/formwidgets.cpp index b75ba5123..44f29e9da 100644 --- a/ui/formwidgets.cpp +++ b/ui/formwidgets.cpp @@ -1,1059 +1,1140 @@ /*************************************************************************** * Copyright (C) 2007 by Pino Toscano * * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group * * company, info@kdab.com. Work sponsored by the * * LiMux project of the city of Munich * + * Copyright (C) 2018 Intevation GmbH * * * * 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. * ***************************************************************************/ #include "formwidgets.h" #include "pageviewutils.h" #include #include #include #include #include #include #include #include #include // local includes #include "core/form.h" #include "core/document.h" #include "debug_ui.h" FormWidgetsController::FormWidgetsController( Okular::Document *doc ) : QObject( doc ), m_doc( doc ) { // emit changed signal when a form has changed connect( this, &FormWidgetsController::formTextChangedByUndoRedo, this, &FormWidgetsController::changed ); connect( this, &FormWidgetsController::formListChangedByUndoRedo, this, &FormWidgetsController::changed ); connect( this, &FormWidgetsController::formComboChangedByUndoRedo, this, &FormWidgetsController::changed ); // connect form modification signals to and from document connect( this, &FormWidgetsController::formTextChangedByWidget, doc, &Okular::Document::editFormText ); connect( doc, &Okular::Document::formTextChangedByUndoRedo, this, &FormWidgetsController::formTextChangedByUndoRedo ); connect( this, &FormWidgetsController::formListChangedByWidget, doc, &Okular::Document::editFormList ); connect( doc, &Okular::Document::formListChangedByUndoRedo, this, &FormWidgetsController::formListChangedByUndoRedo ); connect( this, &FormWidgetsController::formComboChangedByWidget, doc, &Okular::Document::editFormCombo ); connect( doc, &Okular::Document::formComboChangedByUndoRedo, this, &FormWidgetsController::formComboChangedByUndoRedo ); connect( this, &FormWidgetsController::formButtonsChangedByWidget, doc, &Okular::Document::editFormButtons ); connect( doc, &Okular::Document::formButtonsChangedByUndoRedo, this, &FormWidgetsController::slotFormButtonsChangedByUndoRedo ); // Connect undo/redo signals connect( this, &FormWidgetsController::requestUndo, doc, &Okular::Document::undo ); connect( this, &FormWidgetsController::requestRedo, doc, &Okular::Document::redo ); connect( doc, &Okular::Document::canUndoChanged, this, &FormWidgetsController::canUndoChanged ); connect( doc, &Okular::Document::canRedoChanged, this, &FormWidgetsController::canRedoChanged ); // Connect the generic formWidget refresh signal connect( doc, &Okular::Document::refreshFormWidget, this, &FormWidgetsController::refreshFormWidget ); } FormWidgetsController::~FormWidgetsController() { } void FormWidgetsController::signalAction( Okular::Action *a ) { emit action( a ); } void FormWidgetsController::registerRadioButton( FormWidgetIface *fwButton, Okular::FormFieldButton *formButton ) { if ( !fwButton ) return; QAbstractButton *button = dynamic_cast(fwButton); if ( !button ) { qWarning() << "fwButton is not a QAbstractButton" << fwButton; return; } QList< RadioData >::iterator it = m_radios.begin(), itEnd = m_radios.end(); const int id = formButton->id(); m_buttons.insert( id, button ); for ( ; it != itEnd; ++it ) { const QList< int >::const_iterator idsIt = qFind( (*it).ids, id ); if ( idsIt != (*it).ids.constEnd() ) { qCDebug(OkularUiDebug) << "Adding id" << id << "To group including" << (*it).ids; (*it).group->addButton( button ); (*it).group->setId( button, id ); return; } } const QList< int > siblings = formButton->siblings(); RadioData newdata; newdata.ids = siblings; newdata.ids.append( id ); newdata.group = new QButtonGroup(); newdata.group->addButton( button ); newdata.group->setId( button, id ); // Groups of 1 (like checkboxes) can't be exclusive if (siblings.isEmpty()) newdata.group->setExclusive( false ); connect( newdata.group, SIGNAL( buttonClicked(QAbstractButton* ) ), this, SLOT( slotButtonClicked( QAbstractButton* ) ) ); m_radios.append( newdata ); } void FormWidgetsController::dropRadioButtons() { QList< RadioData >::iterator it = m_radios.begin(), itEnd = m_radios.end(); for ( ; it != itEnd; ++it ) { delete (*it).group; } m_radios.clear(); m_buttons.clear(); } bool FormWidgetsController::canUndo() { return m_doc->canUndo(); } bool FormWidgetsController::canRedo() { return m_doc->canRedo(); } void FormWidgetsController::slotButtonClicked( QAbstractButton *button ) { int pageNumber = -1; CheckBoxEdit *check = qobject_cast< CheckBoxEdit * >( button ); if ( check ) { // Checkboxes need to be uncheckable so if clicking a checked one // disable the exclusive status temporarily and uncheck it Okular::FormFieldButton *formButton = static_cast( check->formField() ); if ( formButton->state() ) { const bool wasExclusive = button->group()->exclusive(); button->group()->setExclusive(false); check->setChecked(false); button->group()->setExclusive(wasExclusive); } pageNumber = check->pageItem()->pageNumber(); } else if ( RadioButtonEdit *radio = qobject_cast< RadioButtonEdit * >( button ) ) { pageNumber = radio->pageItem()->pageNumber(); } const QList< QAbstractButton* > buttons = button->group()->buttons(); QList< bool > checked; QList< bool > prevChecked; QList< Okular::FormFieldButton*> formButtons; foreach ( QAbstractButton* button, buttons ) { checked.append( button->isChecked() ); Okular::FormFieldButton *formButton = static_cast( dynamic_cast(button)->formField() ); formButtons.append( formButton ); prevChecked.append( formButton->state() ); } if (checked != prevChecked) emit formButtonsChangedByWidget( pageNumber, formButtons, checked ); if ( check ) { // The formButtonsChangedByWidget signal changes the value of the underlying // Okular::FormField of the checkbox. We need to execute the activiation // action after this. check->doActivateAction(); } } void FormWidgetsController::slotFormButtonsChangedByUndoRedo( int pageNumber, const QList< Okular::FormFieldButton* > & formButtons) { foreach ( Okular::FormFieldButton* formButton, formButtons ) { int id = formButton->id(); QAbstractButton* button = m_buttons[id]; CheckBoxEdit *check = qobject_cast< CheckBoxEdit * >( button ); if ( check ) { emit refreshFormWidget( check->formField() ); } // temporarily disable exclusiveness of the button group // since it breaks doing/redoing steps into which all the checkboxes // are unchecked const bool wasExclusive = button->group()->exclusive(); button->group()->setExclusive(false); bool checked = formButton->state(); button->setChecked( checked ); button->group()->setExclusive(wasExclusive); button->setFocus(); } emit changed( pageNumber ); } FormWidgetIface * FormWidgetFactory::createWidget( Okular::FormField * ff, QWidget * parent ) { FormWidgetIface * widget = nullptr; switch ( ff->type() ) { case Okular::FormField::FormButton: { Okular::FormFieldButton * ffb = static_cast< Okular::FormFieldButton * >( ff ); switch ( ffb->buttonType() ) { case Okular::FormFieldButton::Push: widget = new PushButtonEdit( ffb, parent ); break; case Okular::FormFieldButton::CheckBox: widget = new CheckBoxEdit( ffb, parent ); break; case Okular::FormFieldButton::Radio: widget = new RadioButtonEdit( ffb, parent ); break; default: ; } break; } case Okular::FormField::FormText: { Okular::FormFieldText * fft = static_cast< Okular::FormFieldText * >( ff ); switch ( fft->textType() ) { case Okular::FormFieldText::Multiline: widget = new TextAreaEdit( fft, parent ); break; case Okular::FormFieldText::Normal: widget = new FormLineEdit( fft, parent ); break; case Okular::FormFieldText::FileSelect: widget = new FileEdit( fft, parent ); break; } break; } case Okular::FormField::FormChoice: { Okular::FormFieldChoice * ffc = static_cast< Okular::FormFieldChoice * >( ff ); switch ( ffc->choiceType() ) { case Okular::FormFieldChoice::ListBox: widget = new ListEdit( ffc, parent ); break; case Okular::FormFieldChoice::ComboBox: widget = new ComboEdit( ffc, parent ); break; } break; } default: ; } if ( ff->isReadOnly() ) widget->setVisibility( false ); return widget; } FormWidgetIface::FormWidgetIface( QWidget * w, Okular::FormField * ff ) : m_controller( nullptr ), m_ff( ff ), m_widget( w ), m_pageItem( nullptr ) { } FormWidgetIface::~FormWidgetIface() { m_ff = nullptr; } Okular::NormalizedRect FormWidgetIface::rect() const { return m_ff->rect(); } void FormWidgetIface::setWidthHeight( int w, int h ) { m_widget->resize( w, h ); } void FormWidgetIface::moveTo( int x, int y ) { m_widget->move( x, y ); } bool FormWidgetIface::setVisibility( bool visible ) { bool hadfocus = m_widget->hasFocus(); if ( hadfocus ) m_widget->clearFocus(); m_widget->setVisible( visible ); return hadfocus; } void FormWidgetIface::setCanBeFilled( bool fill ) { m_widget->setEnabled( fill ); } void FormWidgetIface::setPageItem( PageViewItem *pageItem ) { m_pageItem = pageItem; } void FormWidgetIface::setFormField( Okular::FormField *field ) { m_ff = field; } Okular::FormField* FormWidgetIface::formField() const { return m_ff; } PageViewItem* FormWidgetIface::pageItem() const { return m_pageItem; } void FormWidgetIface::setFormWidgetsController( FormWidgetsController *controller ) { m_controller = controller; QObject *obj = dynamic_cast< QObject * > ( this ); QObject::connect( m_controller, &FormWidgetsController::refreshFormWidget, obj, [this] ( Okular::FormField *form ) { slotRefresh ( form ); }); } void FormWidgetIface::slotRefresh( Okular::FormField * form ) { if ( m_ff != form ) { return; } setVisibility( form->isVisible() && !form->isReadOnly() ); m_widget->setEnabled( !form->isReadOnly() ); } PushButtonEdit::PushButtonEdit( Okular::FormFieldButton * button, QWidget * parent ) : QPushButton( parent ), FormWidgetIface( this, button ) { setText( button->caption() ); setVisible( button->isVisible() ); setCursor( Qt::ArrowCursor ); - - connect( this, &QAbstractButton::clicked, this, &PushButtonEdit::slotClicked ); -} - -void PushButtonEdit::slotClicked() -{ - if ( m_ff->activationAction() ) - m_controller->signalAction( m_ff->activationAction() ); } CheckBoxEdit::CheckBoxEdit( Okular::FormFieldButton * button, QWidget * parent ) : QCheckBox( parent ), FormWidgetIface( this, button ) { setText( button->caption() ); setVisible( button->isVisible() ); setCursor( Qt::ArrowCursor ); } void CheckBoxEdit::setFormWidgetsController( FormWidgetsController *controller ) { Okular::FormFieldButton *form = static_cast(m_ff); FormWidgetIface::setFormWidgetsController( controller ); m_controller->registerRadioButton( this, form ); setChecked( form->state() ); } void CheckBoxEdit::doActivateAction() { Okular::FormFieldButton *form = static_cast(m_ff); if ( form->activationAction() ) m_controller->signalAction( form->activationAction() ); } void CheckBoxEdit::slotRefresh( Okular::FormField * form ) { if ( form != m_ff ) { return; } FormWidgetIface::slotRefresh( form ); Okular::FormFieldButton *button = static_cast(m_ff); bool oldState = isChecked(); bool newState = button->state(); if ( oldState != newState ) { setChecked( button->state() ); doActivateAction(); } } RadioButtonEdit::RadioButtonEdit( Okular::FormFieldButton * button, QWidget * parent ) : QRadioButton( parent ), FormWidgetIface( this, button ) { setText( button->caption() ); setVisible( button->isVisible() ); setCursor( Qt::ArrowCursor ); } void RadioButtonEdit::setFormWidgetsController( FormWidgetsController *controller ) { Okular::FormFieldButton *form = static_cast(m_ff); FormWidgetIface::setFormWidgetsController( controller ); m_controller->registerRadioButton( this, form ); setChecked( form->state() ); } FormLineEdit::FormLineEdit( Okular::FormFieldText * text, QWidget * parent ) : QLineEdit( parent ), FormWidgetIface( this, text ) { int maxlen = text->maximumLength(); if ( maxlen >= 0 ) setMaxLength( maxlen ); setAlignment( text->textAlignment() ); setText( text->text() ); if ( text->isPassword() ) setEchoMode( QLineEdit::Password ); m_prevCursorPos = cursorPosition(); m_prevAnchorPos = cursorPosition(); connect( this, &QLineEdit::textEdited, this, &FormLineEdit::slotChanged ); connect( this, &QLineEdit::cursorPositionChanged, this, &FormLineEdit::slotChanged ); setVisible( text->isVisible() ); } void FormLineEdit::setFormWidgetsController(FormWidgetsController* controller) { FormWidgetIface::setFormWidgetsController(controller); connect( m_controller, &FormWidgetsController::formTextChangedByUndoRedo, this, &FormLineEdit::slotHandleTextChangedByUndoRedo ); } bool FormLineEdit::event( QEvent* e ) { if ( e->type() == QEvent::KeyPress ) { QKeyEvent *keyEvent = static_cast< QKeyEvent* >( e ); if ( keyEvent == QKeySequence::Undo ) { emit m_controller->requestUndo(); return true; } else if ( keyEvent == QKeySequence::Redo ) { emit m_controller->requestRedo(); return true; } } return QLineEdit::event( e ); } void FormLineEdit::contextMenuEvent( QContextMenuEvent* event ) { QMenu *menu = createStandardContextMenu(); QList actionList = menu->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, DeleteAct, SelectAllAct }; QAction *kundo = KStandardAction::create( KStandardAction::Undo, m_controller, SIGNAL( requestUndo() ), menu ); QAction *kredo = KStandardAction::create( KStandardAction::Redo, m_controller, SIGNAL( requestRedo() ), menu ); connect( m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled ); connect( m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled ); kundo->setEnabled( m_controller->canUndo() ); kredo->setEnabled( m_controller->canRedo() ); QAction *oldUndo, *oldRedo; oldUndo = actionList[UndoAct]; oldRedo = actionList[RedoAct]; menu->insertAction( oldUndo, kundo ); menu->insertAction( oldRedo, kredo ); menu->removeAction( oldUndo ); menu->removeAction( oldRedo ); menu->exec( event->globalPos() ); delete menu; } void FormLineEdit::slotChanged() { Okular::FormFieldText *form = static_cast(m_ff); QString contents = text(); int cursorPos = cursorPosition(); if ( contents != form->text() ) { m_controller->formTextChangedByWidget( pageItem()->pageNumber(), form, contents, cursorPos, m_prevCursorPos, m_prevAnchorPos ); } m_prevCursorPos = cursorPos; m_prevAnchorPos = cursorPos; if ( hasSelectedText() ) { if ( cursorPos == selectionStart() ) { m_prevAnchorPos = selectionStart() + selectedText().size(); } else { m_prevAnchorPos = selectionStart(); } } } void FormLineEdit::slotHandleTextChangedByUndoRedo( int pageNumber, Okular::FormFieldText* textForm, const QString & contents, int cursorPos, int anchorPos ) { Q_UNUSED(pageNumber); if ( textForm != m_ff || contents == text() ) { return; } disconnect( this, &QLineEdit::cursorPositionChanged, this, &FormLineEdit::slotChanged ); setText(contents); setCursorPosition(anchorPos); cursorForward( true, cursorPos - anchorPos ); connect( this, &QLineEdit::cursorPositionChanged, this, &FormLineEdit::slotChanged ); m_prevCursorPos = cursorPos; m_prevAnchorPos = anchorPos; setFocus(); } void FormLineEdit::slotRefresh( Okular::FormField *form ) { if (form != m_ff) { return; } FormWidgetIface::slotRefresh( form ); Okular::FormFieldText *text = static_cast ( form ); setText( text->text() ); } TextAreaEdit::TextAreaEdit( Okular::FormFieldText * text, QWidget * parent ) : KTextEdit( parent ), FormWidgetIface( this, text ) { setAcceptRichText( text->isRichText() ); setCheckSpellingEnabled( text->canBeSpellChecked() ); setAlignment( text->textAlignment() ); setPlainText( text->text() ); setUndoRedoEnabled( false ); connect( this, &QTextEdit::textChanged, this, &TextAreaEdit::slotChanged ); connect( this, &QTextEdit::cursorPositionChanged, this, &TextAreaEdit::slotChanged ); connect( this, &KTextEdit::aboutToShowContextMenu, this, &TextAreaEdit::slotUpdateUndoAndRedoInContextMenu ); m_prevCursorPos = textCursor().position(); m_prevAnchorPos = textCursor().anchor(); setVisible( text->isVisible() ); } bool TextAreaEdit::event( QEvent* e ) { if ( e->type() == QEvent::KeyPress ) { QKeyEvent *keyEvent = static_cast< QKeyEvent* >(e); if ( keyEvent == QKeySequence::Undo ) { emit m_controller->requestUndo(); return true; } else if ( keyEvent == QKeySequence::Redo ) { emit m_controller->requestRedo(); return true; } } return KTextEdit::event( e ); } void TextAreaEdit::slotUpdateUndoAndRedoInContextMenu( QMenu* menu ) { if ( !menu ) return; QList actionList = menu->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, ClearAct, SelectAllAct, NCountActs }; QAction *kundo = KStandardAction::create( KStandardAction::Undo, m_controller, SIGNAL( requestUndo() ), menu ); QAction *kredo = KStandardAction::create( KStandardAction::Redo, m_controller, SIGNAL( requestRedo() ), menu ); connect(m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled ); connect(m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled ); kundo->setEnabled( m_controller->canUndo() ); kredo->setEnabled( m_controller->canRedo() ); QAction *oldUndo, *oldRedo; oldUndo = actionList[UndoAct]; oldRedo = actionList[RedoAct]; menu->insertAction( oldUndo, kundo ); menu->insertAction( oldRedo, kredo ); menu->removeAction( oldUndo ); menu->removeAction( oldRedo ); } void TextAreaEdit::setFormWidgetsController( FormWidgetsController* controller ) { FormWidgetIface::setFormWidgetsController( controller ); connect( m_controller, &FormWidgetsController::formTextChangedByUndoRedo, this, &TextAreaEdit::slotHandleTextChangedByUndoRedo ); } void TextAreaEdit::slotHandleTextChangedByUndoRedo( int pageNumber, Okular::FormFieldText* textForm, const QString & contents, int cursorPos, int anchorPos ) { Q_UNUSED(pageNumber); if ( textForm != m_ff ) { return; } setPlainText( contents ); QTextCursor c = textCursor(); c.setPosition( anchorPos ); c.setPosition( cursorPos,QTextCursor::KeepAnchor ); m_prevCursorPos = cursorPos; m_prevAnchorPos = anchorPos; setTextCursor( c ); setFocus(); } void TextAreaEdit::slotChanged() { // happens on destruction if (!m_ff) return; Okular::FormFieldText *form = static_cast(m_ff); QString contents = toPlainText(); int cursorPos = textCursor().position(); if (contents != form->text()) { m_controller->formTextChangedByWidget( pageItem()->pageNumber(), form, contents, cursorPos, m_prevCursorPos, m_prevAnchorPos ); } m_prevCursorPos = cursorPos; m_prevAnchorPos = textCursor().anchor(); } void TextAreaEdit::slotRefresh( Okular::FormField *form ) { if (form != m_ff) { return; } FormWidgetIface::slotRefresh( form ); Okular::FormFieldText *text = static_cast ( form ); setPlainText( text->text() ); } FileEdit::FileEdit( Okular::FormFieldText * text, QWidget * parent ) : KUrlRequester( parent ), FormWidgetIface( this, text ) { setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly ); setFilter( i18n( "*|All Files" ) ); setUrl( QUrl::fromUserInput( text->text() ) ); lineEdit()->setAlignment( text->textAlignment() ); m_prevCursorPos = lineEdit()->cursorPosition(); m_prevAnchorPos = lineEdit()->cursorPosition(); connect( this, &KUrlRequester::textChanged, this, &FileEdit::slotChanged ); connect( lineEdit(), &QLineEdit::cursorPositionChanged, this, &FileEdit::slotChanged ); setVisible( text->isVisible() ); } void FileEdit::setFormWidgetsController( FormWidgetsController* controller ) { FormWidgetIface::setFormWidgetsController( controller ); connect( m_controller, &FormWidgetsController::formTextChangedByUndoRedo, this, &FileEdit::slotHandleFileChangedByUndoRedo ); } bool FileEdit::eventFilter( QObject* obj, QEvent* event ) { if ( obj == lineEdit() ) { if ( event->type() == QEvent::KeyPress ) { QKeyEvent *keyEvent = static_cast< QKeyEvent* >( event ); if ( keyEvent == QKeySequence::Undo ) { emit m_controller->requestUndo(); return true; } else if ( keyEvent == QKeySequence::Redo ) { emit m_controller->requestRedo(); return true; } } else if( event->type() == QEvent::ContextMenu ) { QContextMenuEvent *contextMenuEvent = static_cast< QContextMenuEvent* >( event ); QMenu *menu = ( (QLineEdit*) lineEdit() )->createStandardContextMenu(); QList< QAction* > actionList = menu->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, DeleteAct, SelectAllAct }; QAction *kundo = KStandardAction::create( KStandardAction::Undo, m_controller, SIGNAL( requestUndo() ), menu ); QAction *kredo = KStandardAction::create( KStandardAction::Redo, m_controller, SIGNAL( requestRedo() ), menu ); connect(m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled ); connect(m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled ); kundo->setEnabled( m_controller->canUndo() ); kredo->setEnabled( m_controller->canRedo() ); QAction *oldUndo, *oldRedo; oldUndo = actionList[UndoAct]; oldRedo = actionList[RedoAct]; menu->insertAction( oldUndo, kundo ); menu->insertAction( oldRedo, kredo ); menu->removeAction( oldUndo ); menu->removeAction( oldRedo ); menu->exec( contextMenuEvent->globalPos() ); delete menu; return true; } } return KUrlRequester::eventFilter( obj, event ); } void FileEdit::slotChanged() { // Make sure line edit's text matches url expansion if ( text() != url().toLocalFile() ) this->setText( url().toLocalFile() ); Okular::FormFieldText *form = static_cast(m_ff); QString contents = text(); int cursorPos = lineEdit()->cursorPosition(); if (contents != form->text()) { m_controller->formTextChangedByWidget( pageItem()->pageNumber(), form, contents, cursorPos, m_prevCursorPos, m_prevAnchorPos ); } m_prevCursorPos = cursorPos; m_prevAnchorPos = cursorPos; if ( lineEdit()->hasSelectedText() ) { if ( cursorPos == lineEdit()->selectionStart() ) { m_prevAnchorPos = lineEdit()->selectionStart() + lineEdit()->selectedText().size(); } else { m_prevAnchorPos = lineEdit()->selectionStart(); } } } void FileEdit::slotHandleFileChangedByUndoRedo( int pageNumber, Okular::FormFieldText* form, const QString & contents, int cursorPos, int anchorPos ) { Q_UNUSED(pageNumber); if ( form != m_ff || contents == text() ) { return; } disconnect( this, SIGNAL( cursorPositionChanged( int, int ) ), this, SLOT( slotChanged() ) ); setText( contents ); lineEdit()->setCursorPosition( anchorPos ); lineEdit()->cursorForward( true, cursorPos - anchorPos ); connect( this, SIGNAL(cursorPositionChanged( int, int ) ), this, SLOT( slotChanged() ) ); m_prevCursorPos = cursorPos; m_prevAnchorPos = anchorPos; setFocus(); } ListEdit::ListEdit( Okular::FormFieldChoice * choice, QWidget * parent ) : QListWidget( parent ), FormWidgetIface( this, choice ) { addItems( choice->choices() ); setSelectionMode( choice->multiSelect() ? QAbstractItemView::ExtendedSelection : QAbstractItemView::SingleSelection ); setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); QList< int > selectedItems = choice->currentChoices(); if ( choice->multiSelect() ) { foreach ( int index, selectedItems ) if ( index >= 0 && index < count() ) item( index )->setSelected( true ); } else { if ( selectedItems.count() == 1 && selectedItems.at(0) >= 0 && selectedItems.at(0) < count() ) { setCurrentRow( selectedItems.at(0) ); scrollToItem( item( selectedItems.at(0) ) ); } } connect( this, &QListWidget::itemSelectionChanged, this, &ListEdit::slotSelectionChanged ); setVisible( choice->isVisible() ); setCursor( Qt::ArrowCursor ); } void ListEdit::setFormWidgetsController( FormWidgetsController* controller ) { FormWidgetIface::setFormWidgetsController( controller ); connect( m_controller, &FormWidgetsController::formListChangedByUndoRedo, this, &ListEdit::slotHandleFormListChangedByUndoRedo ); } void ListEdit::slotSelectionChanged() { QList< QListWidgetItem * > selection = selectedItems(); QList< int > rows; foreach( const QListWidgetItem * item, selection ) rows.append( row( item ) ); Okular::FormFieldChoice *form = static_cast(m_ff); if ( rows != form->currentChoices() ) { m_controller->formListChangedByWidget( pageItem()->pageNumber(), form, rows ); } } void ListEdit::slotHandleFormListChangedByUndoRedo( int pageNumber, Okular::FormFieldChoice* listForm, const QList< int > & choices ) { Q_UNUSED(pageNumber); if ( m_ff != listForm ) { return; } disconnect( this, &QListWidget::itemSelectionChanged, this, &ListEdit::slotSelectionChanged ); for(int i=0; i < count(); i++) { item( i )->setSelected( choices.contains(i) ); } connect( this, &QListWidget::itemSelectionChanged, this, &ListEdit::slotSelectionChanged ); setFocus(); } ComboEdit::ComboEdit( Okular::FormFieldChoice * choice, QWidget * parent ) : QComboBox( parent ), FormWidgetIface( this, choice ) { addItems( choice->choices() ); setEditable( true ); setInsertPolicy( NoInsert ); lineEdit()->setReadOnly( !choice->isEditable() ); QList< int > selectedItems = choice->currentChoices(); if ( selectedItems.count() == 1 && selectedItems.at(0) >= 0 && selectedItems.at(0) < count() ) setCurrentIndex( selectedItems.at(0) ); if ( choice->isEditable() && !choice->editChoice().isEmpty() ) lineEdit()->setText( choice->editChoice() ); connect( this, SIGNAL(currentIndexChanged(int)), this, SLOT(slotValueChanged()) ); connect( this, &QComboBox::editTextChanged, this, &ComboEdit::slotValueChanged ); connect( lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged ); setVisible( choice->isVisible() ); setCursor( Qt::ArrowCursor ); m_prevCursorPos = lineEdit()->cursorPosition(); m_prevAnchorPos = lineEdit()->cursorPosition(); } void ComboEdit::setFormWidgetsController(FormWidgetsController* controller) { FormWidgetIface::setFormWidgetsController(controller); connect( m_controller, &FormWidgetsController::formComboChangedByUndoRedo, this, &ComboEdit::slotHandleFormComboChangedByUndoRedo); } void ComboEdit::slotValueChanged() { const QString text = lineEdit()->text(); Okular::FormFieldChoice *form = static_cast(m_ff); QString prevText; if ( form->currentChoices().isEmpty() ) { prevText = form->editChoice(); } else { prevText = form->choices()[form->currentChoices()[0]]; } int cursorPos = lineEdit()->cursorPosition(); if ( text != prevText ) { m_controller->formComboChangedByWidget( pageItem()->pageNumber(), form, currentText(), cursorPos, m_prevCursorPos, m_prevAnchorPos ); } prevText = text; m_prevCursorPos = cursorPos; m_prevAnchorPos = cursorPos; if ( lineEdit()->hasSelectedText() ) { if ( cursorPos == lineEdit()->selectionStart() ) { m_prevAnchorPos = lineEdit()->selectionStart() + lineEdit()->selectedText().size(); } else { m_prevAnchorPos = lineEdit()->selectionStart(); } } } void ComboEdit::slotHandleFormComboChangedByUndoRedo( int pageNumber, Okular::FormFieldChoice* form, const QString & text, int cursorPos, int anchorPos ) { Q_UNUSED(pageNumber); if ( m_ff != form ) { return; } // Determine if text corrisponds to an index choices int index = -1; for ( int i = 0; i < count(); i++ ) { if ( itemText(i) == text ) { index = i; } } m_prevCursorPos = cursorPos; m_prevAnchorPos = anchorPos; disconnect( lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged ); const bool isCustomValue = index == -1; if ( isCustomValue ) { setEditText( text ); } else { setCurrentIndex( index ); } lineEdit()->setCursorPosition( anchorPos ); lineEdit()->cursorForward( true, cursorPos - anchorPos ); connect( lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged ); setFocus(); } void ComboEdit::contextMenuEvent( QContextMenuEvent* event ) { QMenu *menu = lineEdit()->createStandardContextMenu(); QList actionList = menu->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, DeleteAct, SelectAllAct }; QAction *kundo = KStandardAction::create( KStandardAction::Undo, m_controller, SIGNAL( requestUndo() ), menu ); QAction *kredo = KStandardAction::create( KStandardAction::Redo, m_controller, SIGNAL( requestRedo() ), menu ); connect( m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled ); connect( m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled ); kundo->setEnabled( m_controller->canUndo() ); kredo->setEnabled( m_controller->canRedo() ); QAction *oldUndo, *oldRedo; oldUndo = actionList[UndoAct]; oldRedo = actionList[RedoAct]; menu->insertAction( oldUndo, kundo ); menu->insertAction( oldRedo, kredo ); menu->removeAction( oldUndo ); menu->removeAction( oldRedo ); menu->exec( event->globalPos() ); delete menu; } bool ComboEdit::event( QEvent* e ) { if ( e->type() == QEvent::KeyPress ) { QKeyEvent *keyEvent = static_cast< QKeyEvent* >(e); if ( keyEvent == QKeySequence::Undo ) { emit m_controller->requestUndo(); return true; } else if ( keyEvent == QKeySequence::Redo ) { emit m_controller->requestRedo(); return true; } } return QComboBox::event( e ); } +// Code for additional action handling. +// Challenge: Change preprocessor magic to C++ magic! +// +// The mouseRelease event is special because the PDF spec +// says that the activation action takes precedence over this. +// So the mouse release action is only signaled if no activation +// action exists. +// +// For checkboxes the activation action is not triggered as +// they are still triggered from the clicked signal and additionally +// when the checked state changes. + +#define DEFINE_ADDITIONAL_ACTIONS(FormClass, BaseClass) \ + void FormClass::mousePressEvent( QMouseEvent *event ) \ + { \ + Okular::Action *act = m_ff->additionalAction( Okular::Annotation::MousePressed ); \ + if ( act ) \ + { \ + m_controller->signalAction( act ); \ + } \ + BaseClass::mousePressEvent( event ); \ + } \ + void FormClass::mouseReleaseEvent( QMouseEvent *event ) \ + { \ + if ( !QWidget::rect().contains( event->localPos().toPoint() ) ) \ + { \ + BaseClass::mouseReleaseEvent( event ); \ + return; \ + } \ + Okular::Action *act = m_ff->activationAction(); \ + if ( act && !qobject_cast< CheckBoxEdit* > ( this ) ) \ + { \ + m_controller->signalAction( act ); \ + } \ + else if ( ( act = m_ff->additionalAction( Okular::Annotation::MouseReleased ) ) ) \ + { \ + m_controller->signalAction( act ); \ + } \ + BaseClass::mouseReleaseEvent( event ); \ + } \ + void FormClass::focusInEvent( QFocusEvent *event ) \ + { \ + Okular::Action *act = m_ff->additionalAction( Okular::Annotation::FocusIn ); \ + if ( act ) \ + { \ + m_controller->signalAction( act ); \ + } \ + BaseClass::focusInEvent( event ); \ + } \ + void FormClass::focusOutEvent( QFocusEvent *event ) \ + { \ + Okular::Action *act = m_ff->additionalAction( Okular::Annotation::FocusOut ); \ + if ( act ) \ + { \ + m_controller->signalAction( act ); \ + } \ + BaseClass::focusOutEvent( event ); \ + } \ + void FormClass::leaveEvent( QEvent *event ) \ + { \ + Okular::Action *act = m_ff->additionalAction( Okular::Annotation::CursorLeaving ); \ + if ( act ) \ + { \ + m_controller->signalAction( act ); \ + } \ + BaseClass::leaveEvent( event ); \ + } \ + void FormClass::enterEvent( QEvent *event ) \ + { \ + Okular::Action *act = m_ff->additionalAction( Okular::Annotation::CursorEntering ); \ + if ( act ) \ + { \ + m_controller->signalAction( act ); \ + } \ + BaseClass::enterEvent( event ); \ + } + +DEFINE_ADDITIONAL_ACTIONS( PushButtonEdit, QPushButton ) +DEFINE_ADDITIONAL_ACTIONS( CheckBoxEdit, QCheckBox ) +DEFINE_ADDITIONAL_ACTIONS( RadioButtonEdit, QRadioButton ) +DEFINE_ADDITIONAL_ACTIONS( FormLineEdit, QLineEdit ) +DEFINE_ADDITIONAL_ACTIONS( TextAreaEdit, KTextEdit ) +DEFINE_ADDITIONAL_ACTIONS( FileEdit, KUrlRequester ) +DEFINE_ADDITIONAL_ACTIONS( ListEdit, QListWidget ) +DEFINE_ADDITIONAL_ACTIONS( ComboEdit, QComboBox ) + +#undef DEFINE_ADDITIONAL_ACTIONS + #include "moc_formwidgets.cpp" diff --git a/ui/formwidgets.h b/ui/formwidgets.h index 22ea721af..e9d3842f1 100644 --- a/ui/formwidgets.h +++ b/ui/formwidgets.h @@ -1,335 +1,351 @@ /*************************************************************************** * Copyright (C) 2007 by Pino Toscano * * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group * * company, info@kdab.com. Work sponsored by the * * LiMux project of the city of Munich * * * * 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_FORMWIDGETS_H_ #define _OKULAR_FORMWIDGETS_H_ #include "core/area.h" #include #include #include #include #include #include #include #include class ComboEdit; class QMenu; class QButtonGroup; class FormWidgetIface; class PageViewItem; class RadioButtonEdit; class QEvent; namespace Okular { class Action; class FormField; class FormFieldButton; class FormFieldChoice; class FormFieldText; class Document; } struct RadioData { RadioData() {} QList< int > ids; QButtonGroup *group; }; class FormWidgetsController : public QObject { Q_OBJECT public: FormWidgetsController( Okular::Document *doc ); virtual ~FormWidgetsController(); void signalAction( Okular::Action *action ); void registerRadioButton( FormWidgetIface *fwButton, Okular::FormFieldButton *formButton ); void dropRadioButtons(); bool canUndo(); bool canRedo(); Q_SIGNALS: void changed( int pageNumber ); void requestUndo(); void requestRedo(); void canUndoChanged( bool undoAvailable ); void canRedoChanged( bool redoAvailable); void formTextChangedByWidget( int pageNumber, Okular::FormFieldText *form, const QString & newContents, int newCursorPos, int prevCursorPos, int prevAnchorPos ); void formTextChangedByUndoRedo( int pageNumber, Okular::FormFieldText *form, const QString & contents, int cursorPos, int anchorPos ); void formListChangedByWidget( int pageNumber, Okular::FormFieldChoice *form, const QList< int > & newChoices ); void formListChangedByUndoRedo( int pageNumber, Okular::FormFieldChoice *form, const QList< int > & choices ); void formComboChangedByWidget( int pageNumber, Okular::FormFieldChoice *form, const QString & newText, int newCursorPos, int prevCursorPos, int prevAnchorPos ); void formComboChangedByUndoRedo( int pageNumber, Okular::FormFieldChoice *form, const QString & text, int cursorPos, int anchorPos ); void formButtonsChangedByWidget( int pageNumber, const QList< Okular::FormFieldButton* > & formButtons, const QList< bool > & newButtonStates ); void action( Okular::Action *action ); void refreshFormWidget( Okular::FormField * form ); private Q_SLOTS: void slotButtonClicked( QAbstractButton *button ); void slotFormButtonsChangedByUndoRedo( int pageNumber, const QList< Okular::FormFieldButton* > & formButtons ); private: friend class TextAreaEdit; friend class FormLineEdit; friend class FileEdit; friend class ListEdit; friend class ComboEdit; QList< RadioData > m_radios; QHash< int, QAbstractButton* > m_buttons; Okular::Document* m_doc; }; class FormWidgetFactory { public: static FormWidgetIface * createWidget( Okular::FormField * ff, QWidget * parent = nullptr ); }; class FormWidgetIface { public: FormWidgetIface( QWidget * w, Okular::FormField * ff ); virtual ~FormWidgetIface(); Okular::NormalizedRect rect() const; void setWidthHeight( int w, int h ); void moveTo( int x, int y ); bool setVisibility( bool visible ); void setCanBeFilled( bool fill ); void setPageItem( PageViewItem *pageItem ); PageViewItem* pageItem() const; void setFormField( Okular::FormField *field ); Okular::FormField* formField() const; virtual void setFormWidgetsController( FormWidgetsController *controller ); protected: virtual void slotRefresh( Okular::FormField *form ); FormWidgetsController * m_controller; Okular::FormField * m_ff; private: QWidget * m_widget; PageViewItem * m_pageItem; }; +#define DECLARE_ADDITIONAL_ACTIONS \ + protected: \ + virtual void mousePressEvent( QMouseEvent *event ) override; \ + virtual void mouseReleaseEvent( QMouseEvent *event ) override; \ + virtual void focusInEvent( QFocusEvent *event ) override; \ + virtual void focusOutEvent( QFocusEvent *event ) override; \ + virtual void leaveEvent( QEvent *event ) override; \ + virtual void enterEvent( QEvent *event ) override; class PushButtonEdit : public QPushButton, public FormWidgetIface { Q_OBJECT public: explicit PushButtonEdit( Okular::FormFieldButton * button, QWidget * parent = nullptr ); - private Q_SLOTS: - void slotClicked(); + DECLARE_ADDITIONAL_ACTIONS }; class CheckBoxEdit : public QCheckBox, public FormWidgetIface { Q_OBJECT public: explicit CheckBoxEdit( Okular::FormFieldButton * button, QWidget * parent = nullptr ); // reimplemented from FormWidgetIface void setFormWidgetsController( FormWidgetsController *controller ) override; void doActivateAction(); protected: void slotRefresh( Okular::FormField *form ) override; + DECLARE_ADDITIONAL_ACTIONS }; class RadioButtonEdit : public QRadioButton, public FormWidgetIface { Q_OBJECT public: explicit RadioButtonEdit( Okular::FormFieldButton * button, QWidget * parent = nullptr ); // reimplemented from FormWidgetIface void setFormWidgetsController( FormWidgetsController *controller ) override; + DECLARE_ADDITIONAL_ACTIONS }; class FormLineEdit : public QLineEdit, public FormWidgetIface { Q_OBJECT public: explicit FormLineEdit( Okular::FormFieldText * text, QWidget * parent = nullptr ); void setFormWidgetsController( FormWidgetsController *controller ) override; bool event ( QEvent * e ) override; void contextMenuEvent( QContextMenuEvent* event ) override; public Q_SLOTS: void slotHandleTextChangedByUndoRedo( int pageNumber, Okular::FormFieldText* textForm, const QString & contents, int cursorPos, int anchorPos ); private Q_SLOTS: void slotChanged(); protected: void slotRefresh( Okular::FormField* form ) override; private: int m_prevCursorPos; int m_prevAnchorPos; + DECLARE_ADDITIONAL_ACTIONS }; class TextAreaEdit : public KTextEdit, public FormWidgetIface { Q_OBJECT public: explicit TextAreaEdit( Okular::FormFieldText * text, QWidget * parent = nullptr ); void setFormWidgetsController( FormWidgetsController *controller ) override; bool event ( QEvent * e ) override; public Q_SLOTS: void slotHandleTextChangedByUndoRedo( int pageNumber, Okular::FormFieldText * textForm, const QString & contents, int cursorPos, int anchorPos ); void slotUpdateUndoAndRedoInContextMenu( QMenu* menu ); private Q_SLOTS: void slotChanged(); protected: void slotRefresh( Okular::FormField* form ) override; private: int m_prevCursorPos; int m_prevAnchorPos; + DECLARE_ADDITIONAL_ACTIONS }; class FileEdit : public KUrlRequester, public FormWidgetIface { Q_OBJECT public: explicit FileEdit( Okular::FormFieldText * text, QWidget * parent = nullptr ); void setFormWidgetsController( FormWidgetsController *controller ) override; protected: bool eventFilter( QObject *obj, QEvent *event ) override; private Q_SLOTS: void slotChanged(); void slotHandleFileChangedByUndoRedo( int pageNumber, Okular::FormFieldText * form, const QString & contents, int cursorPos, int anchorPos ); private: int m_prevCursorPos; int m_prevAnchorPos; + DECLARE_ADDITIONAL_ACTIONS }; class ListEdit : public QListWidget, public FormWidgetIface { Q_OBJECT public: explicit ListEdit( Okular::FormFieldChoice * choice, QWidget * parent = nullptr ); void setFormWidgetsController( FormWidgetsController *controller ) override; private Q_SLOTS: void slotSelectionChanged(); void slotHandleFormListChangedByUndoRedo( int pageNumber, Okular::FormFieldChoice * listForm, const QList< int > & choices ); + DECLARE_ADDITIONAL_ACTIONS }; class ComboEdit : public QComboBox, public FormWidgetIface { Q_OBJECT public: explicit ComboEdit( Okular::FormFieldChoice * choice, QWidget * parent = nullptr ); void setFormWidgetsController( FormWidgetsController *controller ) override; bool event ( QEvent * e ) override; void contextMenuEvent( QContextMenuEvent* event ) override; private Q_SLOTS: void slotValueChanged(); void slotHandleFormComboChangedByUndoRedo( int pageNumber, Okular::FormFieldChoice * comboForm, const QString & text, int cursorPos, int anchorPos ); private: int m_prevCursorPos; int m_prevAnchorPos; + DECLARE_ADDITIONAL_ACTIONS }; +#undef DECLARE_ADDITIONAL_ACTIONS + #endif