blob: 093ddfeebdb4df7fdcf18d5d9da72d2cdb50bbe4 [file] [log] [blame]
/* poppler-form-field.cc: glib interface to poppler
*
* Copyright (C) 2007 Carlos Garcia Campos <carlosgc@gnome.org>
* Copyright (C) 2006 Julien Rebetez
* Copyright (C) 2020 Oliver Sander <oliver.sander@tu-dresden.de>
*
* 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, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <memory>
#include "poppler.h"
#include "poppler-private.h"
/**
* SECTION:poppler-form-field
* @short_description: Form Field
* @title: PopplerFormField
*/
typedef struct _PopplerFormFieldClass PopplerFormFieldClass;
struct _PopplerFormFieldClass
{
GObjectClass parent_class;
};
G_DEFINE_TYPE(PopplerFormField, poppler_form_field, G_TYPE_OBJECT)
static void poppler_form_field_finalize(GObject *object)
{
PopplerFormField *field = POPPLER_FORM_FIELD(object);
if (field->document) {
g_object_unref(field->document);
field->document = nullptr;
}
if (field->action) {
poppler_action_free(field->action);
field->action = nullptr;
}
field->widget = nullptr;
G_OBJECT_CLASS(poppler_form_field_parent_class)->finalize(object);
}
static void poppler_form_field_init(PopplerFormField *field) { }
static void poppler_form_field_class_init(PopplerFormFieldClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
gobject_class->finalize = poppler_form_field_finalize;
}
PopplerFormField *_poppler_form_field_new(PopplerDocument *document, FormWidget *field)
{
PopplerFormField *poppler_field;
g_return_val_if_fail(POPPLER_IS_DOCUMENT(document), NULL);
g_return_val_if_fail(field != nullptr, NULL);
poppler_field = POPPLER_FORM_FIELD(g_object_new(POPPLER_TYPE_FORM_FIELD, nullptr));
poppler_field->document = (PopplerDocument *)g_object_ref(document);
poppler_field->widget = field;
return poppler_field;
}
/* Public methods */
/**
* poppler_form_field_get_field_type:
* @field: a #PopplerFormField
*
* Gets the type of @field
*
* Return value: #PopplerFormFieldType of @field
**/
PopplerFormFieldType poppler_form_field_get_field_type(PopplerFormField *field)
{
g_return_val_if_fail(POPPLER_IS_FORM_FIELD(field), POPPLER_FORM_FIELD_UNKNOWN);
switch (field->widget->getType()) {
case formButton:
return POPPLER_FORM_FIELD_BUTTON;
case formText:
return POPPLER_FORM_FIELD_TEXT;
case formChoice:
return POPPLER_FORM_FIELD_CHOICE;
case formSignature:
return POPPLER_FORM_FIELD_SIGNATURE;
default:
g_warning("Unsupported Form Field Type");
}
return POPPLER_FORM_FIELD_UNKNOWN;
}
/**
* poppler_form_field_get_id:
* @field: a #PopplerFormField
*
* Gets the id of @field
*
* Return value: the id of @field
**/
gint poppler_form_field_get_id(PopplerFormField *field)
{
g_return_val_if_fail(POPPLER_IS_FORM_FIELD(field), -1);
return field->widget->getID();
}
/**
* poppler_form_field_get_font_size:
* @field: a #PopplerFormField
*
* Gets the font size of @field
*
* WARNING: This function always returns 0. Contact the poppler
* mailing list if you're interested in implementing it properly
*
* Return value: the font size of @field
**/
gdouble poppler_form_field_get_font_size(PopplerFormField *field)
{
g_return_val_if_fail(POPPLER_IS_FORM_FIELD(field), 0);
return 0;
}
/**
* poppler_form_field_is_read_only:
* @field: a #PopplerFormField
*
* Checks whether @field is read only
*
* Return value: %TRUE if @field is read only
**/
gboolean poppler_form_field_is_read_only(PopplerFormField *field)
{
g_return_val_if_fail(POPPLER_IS_FORM_FIELD(field), FALSE);
return field->widget->isReadOnly();
}
/**
* poppler_form_field_get_action:
* @field: a #PopplerFormField
*
* Retrieves the action (#PopplerAction) that shall be
* performed when @field is activated, or %NULL
*
* Return value: (transfer none): the action to perform. The returned
* object is owned by @field and should not be freed
*
* Since: 0.18
*/
PopplerAction *poppler_form_field_get_action(PopplerFormField *field)
{
LinkAction *action;
if (field->action)
return field->action;
action = field->widget->getActivationAction();
if (!action)
return nullptr;
field->action = _poppler_action_new(field->document, action, nullptr);
return field->action;
}
/**
* poppler_form_field_get_additional_action:
* @field: a #PopplerFormField
* @type: the type of additional action
*
* Retrieves the action (#PopplerAction) that shall be performed when
* an additional action is triggered on @field, or %NULL.
*
* Return value: (transfer none): the action to perform. The returned
* object is owned by @field and should not be freed.
*
*
* Since: 0.72
*/
PopplerAction *poppler_form_field_get_additional_action(PopplerFormField *field, PopplerAdditionalActionType type)
{
Annot::FormAdditionalActionsType form_action;
PopplerAction **action;
switch (type) {
case POPPLER_ADDITIONAL_ACTION_FIELD_MODIFIED:
form_action = Annot::actionFieldModified;
action = &field->field_modified_action;
break;
case POPPLER_ADDITIONAL_ACTION_FORMAT_FIELD:
form_action = Annot::actionFormatField;
action = &field->format_field_action;
break;
case POPPLER_ADDITIONAL_ACTION_VALIDATE_FIELD:
form_action = Annot::actionValidateField;
action = &field->validate_field_action;
break;
case POPPLER_ADDITIONAL_ACTION_CALCULATE_FIELD:
form_action = Annot::actionCalculateField;
action = &field->calculate_field_action;
break;
default:
g_return_val_if_reached(nullptr);
return nullptr;
}
if (*action)
return *action;
std::unique_ptr<LinkAction> link_action = field->widget->getAdditionalAction(form_action);
if (!link_action)
return nullptr;
*action = _poppler_action_new(nullptr, link_action.get(), nullptr);
return *action;
}
/* Button Field */
/**
* poppler_form_field_button_get_button_type:
* @field: a #PopplerFormField
*
* Gets the button type of @field
*
* Return value: #PopplerFormButtonType of @field
**/
PopplerFormButtonType poppler_form_field_button_get_button_type(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formButton, POPPLER_FORM_BUTTON_PUSH);
switch (static_cast<FormWidgetButton *>(field->widget)->getButtonType()) {
case formButtonPush:
return POPPLER_FORM_BUTTON_PUSH;
case formButtonCheck:
return POPPLER_FORM_BUTTON_CHECK;
case formButtonRadio:
return POPPLER_FORM_BUTTON_RADIO;
default:
g_assert_not_reached();
}
}
/**
* poppler_form_field_button_get_state:
* @field: a #PopplerFormField
*
* Queries a #PopplerFormField and returns its current state. Returns %TRUE if
* @field is pressed in and %FALSE if it is raised.
*
* Return value: current state of @field
**/
gboolean poppler_form_field_button_get_state(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formButton, FALSE);
return static_cast<FormWidgetButton *>(field->widget)->getState();
}
/**
* poppler_form_field_button_set_state:
* @field: a #PopplerFormField
* @state: %TRUE or %FALSE
*
* Sets the status of @field. Set to %TRUE if you want the #PopplerFormField
* to be 'pressed in', and %FALSE to raise it.
**/
void poppler_form_field_button_set_state(PopplerFormField *field, gboolean state)
{
g_return_if_fail(field->widget->getType() == formButton);
static_cast<FormWidgetButton *>(field->widget)->setState((bool)state);
}
/**
* poppler_form_field_get_partial_name:
* @field: a #PopplerFormField
*
* Gets the partial name of @field.
*
* Return value: a new allocated string. It must be freed with g_free() when done.
*
* Since: 0.16
**/
gchar *poppler_form_field_get_partial_name(PopplerFormField *field)
{
const GooString *tmp;
g_return_val_if_fail(POPPLER_IS_FORM_FIELD(field), NULL);
tmp = field->widget->getPartialName();
return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr;
}
/**
* poppler_form_field_get_mapping_name:
* @field: a #PopplerFormField
*
* Gets the mapping name of @field that is used when
* exporting interactive form field data from the document
*
* Return value: a new allocated string. It must be freed with g_free() when done.
*
* Since: 0.16
**/
gchar *poppler_form_field_get_mapping_name(PopplerFormField *field)
{
const GooString *tmp;
g_return_val_if_fail(POPPLER_IS_FORM_FIELD(field), NULL);
tmp = field->widget->getMappingName();
return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr;
}
/**
* poppler_form_field_get_name:
* @field: a #PopplerFormField
*
* Gets the fully qualified name of @field. It's constructed by concatenating
* the partial field names of the field and all of its ancestors.
*
* Return value: a new allocated string. It must be freed with g_free() when done.
*
* Since: 0.16
**/
gchar *poppler_form_field_get_name(PopplerFormField *field)
{
GooString *tmp;
g_return_val_if_fail(POPPLER_IS_FORM_FIELD(field), NULL);
tmp = field->widget->getFullyQualifiedName();
return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr;
}
/**
* poppler_form_field_get_alternate_ui_name:
* @field: a #PopplerFormField
*
* Gets the alternate ui name of @field. This name is also commonly
* used by pdf producers/readers to show it as a tooltip when @field area
* is hovered by a pointing device (eg. mouse).
*
* Return value: a new allocated string. It must be freed with g_free() when done.
*
* Since: 0.88
**/
gchar *poppler_form_field_get_alternate_ui_name(PopplerFormField *field)
{
const GooString *tmp;
g_return_val_if_fail(POPPLER_IS_FORM_FIELD(field), NULL);
tmp = field->widget->getAlternateUiName();
return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr;
}
/* Text Field */
/**
* poppler_form_field_text_get_text_type:
* @field: a #PopplerFormField
*
* Gets the text type of @field.
*
* Return value: #PopplerFormTextType of @field
**/
PopplerFormTextType poppler_form_field_text_get_text_type(PopplerFormField *field)
{
FormWidgetText *text_field;
g_return_val_if_fail(field->widget->getType() == formText, POPPLER_FORM_TEXT_NORMAL);
text_field = static_cast<FormWidgetText *>(field->widget);
if (text_field->isMultiline())
return POPPLER_FORM_TEXT_MULTILINE;
else if (text_field->isFileSelect())
return POPPLER_FORM_TEXT_FILE_SELECT;
return POPPLER_FORM_TEXT_NORMAL;
}
/**
* poppler_form_field_text_get_text:
* @field: a #PopplerFormField
*
* Retrieves the contents of @field.
*
* Return value: a new allocated string. It must be freed with g_free() when done.
**/
gchar *poppler_form_field_text_get_text(PopplerFormField *field)
{
FormWidgetText *text_field;
const GooString *tmp;
g_return_val_if_fail(field->widget->getType() == formText, NULL);
text_field = static_cast<FormWidgetText *>(field->widget);
tmp = text_field->getContent();
return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr;
}
/**
* poppler_form_field_text_set_text:
* @field: a #PopplerFormField
* @text: the new text
*
* Sets the text in @field to the given value, replacing the current contents.
**/
void poppler_form_field_text_set_text(PopplerFormField *field, const gchar *text)
{
GooString *goo_tmp;
gchar *tmp;
gsize length = 0;
g_return_if_fail(field->widget->getType() == formText);
tmp = text ? g_convert(text, -1, "UTF-16BE", "UTF-8", nullptr, &length, nullptr) : nullptr;
goo_tmp = new GooString(tmp, length);
g_free(tmp);
static_cast<FormWidgetText *>(field->widget)->setContent(goo_tmp);
delete goo_tmp;
}
/**
* poppler_form_field_text_get_max_len:
* @field: a #PopplerFormField
*
* Retrieves the maximum allowed length of the text in @field
*
* Return value: the maximum allowed number of characters in @field, or -1 if there is no maximum.
**/
gint poppler_form_field_text_get_max_len(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formText, 0);
return static_cast<FormWidgetText *>(field->widget)->getMaxLen();
}
/**
* poppler_form_field_text_do_spell_check:
* @field: a #PopplerFormField
*
* Checks whether spell checking should be done for the contents of @field
*
* Return value: %TRUE if spell checking should be done for @field
**/
gboolean poppler_form_field_text_do_spell_check(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formText, FALSE);
return !static_cast<FormWidgetText *>(field->widget)->noSpellCheck();
}
gboolean poppler_form_field_text_do_scroll(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formText, FALSE);
return !static_cast<FormWidgetText *>(field->widget)->noScroll();
}
/**
* poppler_form_field_text_is_rich_text:
* @field: a #PopplerFormField
*
* Checks whether the contents of @field are rich text
*
* Return value: %TRUE if the contents of @field are rich text
**/
gboolean poppler_form_field_text_is_rich_text(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formText, FALSE);
return static_cast<FormWidgetText *>(field->widget)->isRichText();
}
/**
* poppler_form_field_text_is_password:
* @field: a #PopplerFormField
*
* Checks whether content of @field is a password and it must be hidden
*
* Return value: %TRUE if the content of @field is a password
**/
gboolean poppler_form_field_text_is_password(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formText, FALSE);
return static_cast<FormWidgetText *>(field->widget)->isPassword();
}
/* Choice Field */
/**
* poppler_form_field_choice_get_choice_type:
* @field: a #PopplerFormField
*
* Gets the choice type of @field
*
* Return value: #PopplerFormChoiceType of @field
**/
PopplerFormChoiceType poppler_form_field_choice_get_choice_type(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formChoice, POPPLER_FORM_CHOICE_COMBO);
if (static_cast<FormWidgetChoice *>(field->widget)->isCombo())
return POPPLER_FORM_CHOICE_COMBO;
else
return POPPLER_FORM_CHOICE_LIST;
}
/**
* poppler_form_field_choice_is_editable:
* @field: a #PopplerFormField
*
* Checks whether @field is editable
*
* Return value: %TRUE if @field is editable
**/
gboolean poppler_form_field_choice_is_editable(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formChoice, FALSE);
return static_cast<FormWidgetChoice *>(field->widget)->hasEdit();
}
/**
* poppler_form_field_choice_can_select_multiple:
* @field: a #PopplerFormField
*
* Checks whether @field allows multiple choices to be selected
*
* Return value: %TRUE if @field allows multiple choices to be selected
**/
gboolean poppler_form_field_choice_can_select_multiple(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formChoice, FALSE);
return static_cast<FormWidgetChoice *>(field->widget)->isMultiSelect();
}
/**
* poppler_form_field_choice_do_spell_check:
* @field: a #PopplerFormField
*
* Checks whether spell checking should be done for the contents of @field
*
* Return value: %TRUE if spell checking should be done for @field
**/
gboolean poppler_form_field_choice_do_spell_check(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formChoice, FALSE);
return !static_cast<FormWidgetChoice *>(field->widget)->noSpellCheck();
}
gboolean poppler_form_field_choice_commit_on_change(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formChoice, FALSE);
return static_cast<FormWidgetChoice *>(field->widget)->commitOnSelChange();
}
/**
* poppler_form_field_choice_get_n_items:
* @field: a #PopplerFormField
*
* Returns the number of items on @field
*
* Return value: the number of items on @field
**/
gint poppler_form_field_choice_get_n_items(PopplerFormField *field)
{
g_return_val_if_fail(field->widget->getType() == formChoice, -1);
return static_cast<FormWidgetChoice *>(field->widget)->getNumChoices();
}
/**
* poppler_form_field_choice_get_item:
* @field: a #PopplerFormField
* @index: the index of the item
*
* Returns the contents of the item on @field at the given index
*
* Return value: a new allocated string. It must be freed with g_free() when done.
**/
gchar *poppler_form_field_choice_get_item(PopplerFormField *field, gint index)
{
const GooString *tmp;
g_return_val_if_fail(field->widget->getType() == formChoice, NULL);
g_return_val_if_fail(index >= 0 && index < poppler_form_field_choice_get_n_items(field), NULL);
tmp = static_cast<FormWidgetChoice *>(field->widget)->getChoice(index);
return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr;
}
/**
* poppler_form_field_choice_is_item_selected:
* @field: a #PopplerFormField
* @index: the index of the item
*
* Checks whether the item at the given index on @field is currently selected
*
* Return value: %TRUE if item at @index is currently selected
**/
gboolean poppler_form_field_choice_is_item_selected(PopplerFormField *field, gint index)
{
g_return_val_if_fail(field->widget->getType() == formChoice, FALSE);
g_return_val_if_fail(index >= 0 && index < poppler_form_field_choice_get_n_items(field), FALSE);
return static_cast<FormWidgetChoice *>(field->widget)->isSelected(index);
}
/**
* poppler_form_field_choice_select_item:
* @field: a #PopplerFormField
* @index: the index of the item
*
* Selects the item at the given index on @field
**/
void poppler_form_field_choice_select_item(PopplerFormField *field, gint index)
{
g_return_if_fail(field->widget->getType() == formChoice);
g_return_if_fail(index >= 0 && index < poppler_form_field_choice_get_n_items(field));
static_cast<FormWidgetChoice *>(field->widget)->select(index);
}
/**
* poppler_form_field_choice_unselect_all:
* @field: a #PopplerFormField
*
* Unselects all the items on @field
**/
void poppler_form_field_choice_unselect_all(PopplerFormField *field)
{
g_return_if_fail(field->widget->getType() == formChoice);
static_cast<FormWidgetChoice *>(field->widget)->deselectAll();
}
/**
* poppler_form_field_choice_toggle_item:
* @field: a #PopplerFormField
* @index: the index of the item
*
* Changes the state of the item at the given index
**/
void poppler_form_field_choice_toggle_item(PopplerFormField *field, gint index)
{
g_return_if_fail(field->widget->getType() == formChoice);
g_return_if_fail(index >= 0 && index < poppler_form_field_choice_get_n_items(field));
static_cast<FormWidgetChoice *>(field->widget)->toggle(index);
}
/**
* poppler_form_field_choice_set_text:
* @field: a #PopplerFormField
* @text: the new text
*
* Sets the text in @field to the given value, replacing the current contents
**/
void poppler_form_field_choice_set_text(PopplerFormField *field, const gchar *text)
{
GooString *goo_tmp;
gchar *tmp;
gsize length = 0;
g_return_if_fail(field->widget->getType() == formChoice);
tmp = text ? g_convert(text, -1, "UTF-16BE", "UTF-8", nullptr, &length, nullptr) : nullptr;
goo_tmp = new GooString(tmp, length);
g_free(tmp);
static_cast<FormWidgetChoice *>(field->widget)->setEditChoice(goo_tmp);
delete goo_tmp;
}
/**
* poppler_form_field_choice_get_text:
* @field: a #PopplerFormField
*
* Retrieves the contents of @field.
*
* Return value: a new allocated string. It must be freed with g_free() when done.
**/
gchar *poppler_form_field_choice_get_text(PopplerFormField *field)
{
const GooString *tmp;
g_return_val_if_fail(field->widget->getType() == formChoice, NULL);
tmp = static_cast<FormWidgetChoice *>(field->widget)->getEditChoice();
return tmp ? _poppler_goo_string_to_utf8(tmp) : nullptr;
}