diff --git a/core/annotations.h b/core/annotations.h --- a/core/annotations.h +++ b/core/annotations.h @@ -191,8 +191,14 @@ */ 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 }; /** diff --git a/core/form.h b/core/form.h --- a/core/form.h +++ b/core/form.h @@ -12,6 +12,7 @@ #include "okularcore_export.h" #include "area.h" +#include "annotations.h" #include @@ -127,6 +128,14 @@ */ 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 ); @@ -136,6 +145,7 @@ void setActivationAction( Action *action ); void setAdditionalAction( AdditionalActionType type, Action *action ); + void setAdditionalAction( Annotation::AdditionalActionType type, Action *action ); private: Q_DISABLE_COPY( FormField ) diff --git a/core/form.cpp b/core/form.cpp --- a/core/form.cpp +++ b/core/form.cpp @@ -25,6 +25,8 @@ FormFieldPrivate::~FormFieldPrivate() { delete m_activateAction; + qDeleteAll( m_additionalActions.values() ); + qDeleteAll( m_additionalAnnotActions.values() ); } void FormFieldPrivate::setDefault() @@ -94,6 +96,19 @@ 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 { diff --git a/core/form_p.h b/core/form_p.h --- a/core/form_p.h +++ b/core/form_p.h @@ -34,6 +34,7 @@ QString m_default; Action *m_activateAction; QHash m_additionalActions; + QHash m_additionalAnnotActions; Q_DECLARE_PUBLIC( FormField ) FormField *q_ptr; diff --git a/generators/poppler/CMakeLists.txt b/generators/poppler/CMakeLists.txt --- a/generators/poppler/CMakeLists.txt +++ b/generators/poppler/CMakeLists.txt @@ -86,6 +86,16 @@ } " 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 diff --git a/generators/poppler/config-okular-poppler.h.cmake b/generators/poppler/config-okular-poppler.h.cmake --- a/generators/poppler/config-okular-poppler.h.cmake +++ b/generators/poppler/config-okular-poppler.h.cmake @@ -27,3 +27,6 @@ /* 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 --- a/generators/poppler/formfields.cpp +++ b/generators/poppler/formfields.cpp @@ -1,5 +1,6 @@ /*************************************************************************** * 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 * @@ -16,14 +17,26 @@ #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() ) ); diff --git a/ui/formwidgets.h b/ui/formwidgets.h --- a/ui/formwidgets.h +++ b/ui/formwidgets.h @@ -170,16 +170,23 @@ 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 @@ -196,6 +203,7 @@ protected: void slotRefresh( Okular::FormField *form ) override; + DECLARE_ADDITIONAL_ACTIONS }; class RadioButtonEdit : public QRadioButton, public FormWidgetIface @@ -207,6 +215,7 @@ // reimplemented from FormWidgetIface void setFormWidgetsController( FormWidgetsController *controller ) override; + DECLARE_ADDITIONAL_ACTIONS }; class FormLineEdit : public QLineEdit, public FormWidgetIface @@ -235,6 +244,7 @@ private: int m_prevCursorPos; int m_prevAnchorPos; + DECLARE_ADDITIONAL_ACTIONS }; class TextAreaEdit : public KTextEdit, public FormWidgetIface @@ -264,6 +274,7 @@ private: int m_prevCursorPos; int m_prevAnchorPos; + DECLARE_ADDITIONAL_ACTIONS }; @@ -289,6 +300,7 @@ private: int m_prevCursorPos; int m_prevAnchorPos; + DECLARE_ADDITIONAL_ACTIONS }; @@ -305,6 +317,7 @@ void slotHandleFormListChangedByUndoRedo( int pageNumber, Okular::FormFieldChoice * listForm, const QList< int > & choices ); + DECLARE_ADDITIONAL_ACTIONS }; @@ -330,6 +343,9 @@ private: int m_prevCursorPos; int m_prevAnchorPos; + DECLARE_ADDITIONAL_ACTIONS }; +#undef DECLARE_ADDITIONAL_ACTIONS + #endif diff --git a/ui/formwidgets.cpp b/ui/formwidgets.cpp --- a/ui/formwidgets.cpp +++ b/ui/formwidgets.cpp @@ -3,6 +3,7 @@ * 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 * @@ -372,14 +373,6 @@ 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() ); } @@ -1056,4 +1049,91 @@ 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() ) ) \ + { \ + 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"