diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index af7c67c82..d40d56650 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,94 +1,98 @@ add_definitions( -DKDESRCDIR="${CMAKE_CURRENT_SOURCE_DIR}/" ) include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) ecm_add_test(shelltest.cpp ../shell/shellutils.cpp TEST_NAME "shelltest" LINK_LIBRARIES Qt5::Test okularcore ) if(Poppler_Qt5_FOUND) ecm_add_test(parttest.cpp TEST_NAME "parttest" LINK_LIBRARIES Qt5::Widgets Qt5::Test Qt5::Xml okularcore okularpart ) ecm_add_test(visibilitytest.cpp TEST_NAME "visibilitytest" LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore ) ecm_add_test(kjsfunctionstest.cpp TEST_NAME "kjsfunctionstest" LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore ) + ecm_add_test(formattest.cpp + TEST_NAME "formattest" + LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore + ) endif() ecm_add_test(documenttest.cpp TEST_NAME "documenttest" LINK_LIBRARIES Qt5::Widgets Qt5::Test Qt5::Xml okularcore KF5::ThreadWeaver ) ecm_add_test(searchtest.cpp TEST_NAME "searchtest" LINK_LIBRARIES Qt5::Widgets Qt5::Test Qt5::Xml okularcore ) ecm_add_test(annotationstest.cpp TEST_NAME "annotationstest" LINK_LIBRARIES Qt5::Widgets Qt5::Test Qt5::Xml okularcore ) ecm_add_test(urldetecttest.cpp TEST_NAME "urldetecttest" LINK_LIBRARIES Qt5::Widgets Qt5::Test Qt5::Xml KF5::CoreAddons ) ecm_add_test(editannotationcontentstest.cpp testingutils.cpp TEST_NAME "editannotationcontentstest" LINK_LIBRARIES Qt5::Widgets Qt5::Test Qt5::Xml okularcore ) ecm_add_test(addremoveannotationtest.cpp testingutils.cpp TEST_NAME "addremoveannotationtest" LINK_LIBRARIES Qt5::Widgets Qt5::Test Qt5::Xml okularcore ) ecm_add_test(translateannotationtest.cpp testingutils.cpp TEST_NAME "translateannotationtest" LINK_LIBRARIES Qt5::Widgets Qt5::Test Qt5::Xml okularcore ) ecm_add_test(modifyannotationpropertiestest.cpp testingutils.cpp TEST_NAME "modifyannotationpropertiestest" LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore ) ecm_add_test(editformstest.cpp TEST_NAME "editformstest" LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore ) ecm_add_test(calculatetexttest.cpp TEST_NAME "calculatetexttest" LINK_LIBRARIES Qt5::Widgets Qt5::Test okularcore ) if(KF5Activities_FOUND) ecm_add_test(mainshelltest.cpp ../shell/okular_main.cpp ../shell/shellutils.cpp ../shell/shell.cpp TEST_NAME "mainshelltest" LINK_LIBRARIES Qt5::Test KF5::Activities okularpart okularcore ) target_compile_definitions(mainshelltest PRIVATE OKULAR_BINARY="$") endif() ecm_add_test(generatorstest.cpp TEST_NAME "generatorstest" LINK_LIBRARIES Qt5::Test KF5::CoreAddons okularcore ) target_compile_definitions(generatorstest PRIVATE GENERATORS_BUILD_DIR="${CMAKE_BINARY_DIR}/generators") ecm_add_test(signatureformtest.cpp TEST_NAME "signatureformtest" LINK_LIBRARIES Qt5::Test okularcore ) diff --git a/autotests/data/formattest.pdf b/autotests/data/formattest.pdf new file mode 100644 index 000000000..c82ba54fe Binary files /dev/null and b/autotests/data/formattest.pdf differ diff --git a/autotests/formattest.cpp b/autotests/formattest.cpp new file mode 100644 index 000000000..e5b8c5813 --- /dev/null +++ b/autotests/formattest.cpp @@ -0,0 +1,146 @@ +/*************************************************************************** + * Copyright (C) 2019 by João Netto * + * * + * 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 + +#include +#include +#include +#include "../settings_core.h" +#include +#include +#include +#include + +#include "../generators/poppler/config-okular-poppler.h" + +class FormatTest: public QObject +{ + Q_OBJECT + +private slots: + void initTestCase(); + void cleanupTestCase(); + void testTimeFormat(); +private: + + Okular::Document *m_document; + QMap m_fields; + QString m_formattedText; +}; + +void FormatTest::initTestCase() +{ + Okular::SettingsCore::instance( QStringLiteral( "formattest" ) ); + m_document = new Okular::Document( nullptr ); + + const QString testFile = QStringLiteral( KDESRCDIR "data/formattest.pdf" ); + QMimeDatabase db; + const QMimeType mime = db.mimeTypeForFile( testFile ); + QCOMPARE( m_document->openDocument( testFile, QUrl(), mime), Okular::Document::OpenSuccess ); + + connect( m_document, &Okular::Document::refreshFormWidget, [=]( Okular::FormField * form ) + { + Okular::FormFieldText *fft = reinterpret_cast< Okular::FormFieldText * >( form ); + if( fft ) + m_formattedText = fft->text(); + }); + + const Okular::Page* page = m_document->page( 0 ); + for ( Okular::FormField *ff: page->formFields() ) + { + m_fields.insert( ff->name(), ff ); + } +} + +void FormatTest::testTimeFormat() +{ + Okular::FormFieldText *fft = reinterpret_cast< Okular::FormFieldText * >( m_fields[ QStringLiteral( "time1" ) ] ); + + fft->setText( QStringLiteral( "1:20" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "01:20" ), m_formattedText ); + + fft->setText( QStringLiteral( "1:20 pm" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "13:20" ), m_formattedText ); + + fft->setText( QStringLiteral( "1" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "" ), m_formattedText ); + + fft->setText( QStringLiteral( "25:12" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "" ), m_formattedText ); + + fft->setText( QStringLiteral( "abcd" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "" ), m_formattedText ); + + fft = reinterpret_cast< Okular::FormFieldText * >( m_fields[ QStringLiteral( "time2" ) ] ); + + fft->setText( QStringLiteral( "1:20" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "1:20 am" ), m_formattedText ); + + fft->setText( QStringLiteral( "01:20 pm" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "1:20 pm" ), m_formattedText ); + + fft->setText( QStringLiteral( "13:20" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "1:20 pm" ), m_formattedText ); + + fft = reinterpret_cast< Okular::FormFieldText * >( m_fields[ QStringLiteral( "time3" ) ] ); + + fft->setText( QStringLiteral( "1:20" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "01:20:00" ), m_formattedText ); + + fft->setText( QStringLiteral( "1:20:00 pm" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "13:20:00" ), m_formattedText ); + + fft = reinterpret_cast< Okular::FormFieldText * >( m_fields[ QStringLiteral( "time4" ) ] ); + + fft->setText( QStringLiteral( "1:20:00" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "1:20:00 am" ), m_formattedText ); + + fft->setText( QStringLiteral( "01:20:00 pm" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "1:20:00 pm" ), m_formattedText ); + + fft->setText( QStringLiteral( "13:20:00" ) ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( QStringLiteral( "1:20:00 pm" ), m_formattedText ); +} + +void FormatTest::cleanupTestCase() +{ + m_document->closeDocument(); + delete m_document; +} + + +QTEST_MAIN( FormatTest ) +#include "formattest.moc" diff --git a/core/script/builtin.js b/core/script/builtin.js index 2090c942d..a5dcb3904 100644 --- a/core/script/builtin.js +++ b/core/script/builtin.js @@ -1,62 +1,158 @@ /*************************************************************************** * 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. * ***************************************************************************/ /* Builtin functions for Okular's PDF JavaScript interpretation. */ /** AFSimple_Calculate * * cFunction is a string that identifies the operation. * It is one of AVG, SUM, PRD, MIN, MAX * cFields is an array of the names of the fields used to calculate. */ function AFSimple_Calculate( cFunction, cFields ) { var ret = 0; if ( cFunction === "PRD" ) { ret = 1; } for (i = 0; i < cFields.length; i++) { var field = Doc.getField( cFields[i] ); var val = Number( field.value ); if ( cFunction === "SUM" || cFunction === "AVG" ) { ret += val; } else if ( cFunction === "PRD" ) { ret *= val; } else if ( cFunction === "MIN" ) { if ( i === 0 || val < ret ) { ret = val; } } else if ( cFunction === "MAX" ) { if ( i === 0 || val > ret ) { ret = val; } } } if ( cFunction === "AVG" ) { ret /= cFields.length; } event.value = ret; } + +/** AFTime_Format + * + * Formats event.value based on parameters. + * + * Parameter description based on Acrobat Help: + * + * ptf is the number which should be used to format the time, is one of: + * 0 = 24HR_MM [ 14:30 ] + * 1 = 12HR_MM [ 2:30 PM ] + * 2 = 24HR_MM_SS [ 14:30:15 ] + * 3 = 12HR_MM_SS [ 2:30:15 PM ] + */ +function AFTime_Format( ptf ) +{ + if( !event.value ) + { + return; + } + var tokens = event.value.split( /\D/ ); + var invalidDate = false; + + // Remove empty elements of the array + tokens = tokens.filter(Boolean); + + if( tokens.length < 2 ) + invalidDate = true; + + // Check if every number is valid + for( i = 0 ; i < tokens.length ; ++i ) + { + if( isNaN( tokens[i] ) ) + { + invalidDate = true; + break; + } + switch( i ) + { + case 0: + { + if( tokens[i] > 23 || tokens[i] < 0 ) + invalidDate = true; + break; + } + case 1: + case 2: + { + if( tokens[i] > 59 || tokens[i] < 0 ) + invalidDate = true; + break; + } + } + } + if( invalidDate ) + { + event.value = ""; + return; + } + + // Make it of lenght 3, since we use hh, mm, ss + while( tokens.length < 3 ) + tokens.push( 0 ); + + // Add 12 to time if it's PM and less than 12 + if( ( event.value.search( 'PM' ) !== -1 || event.value.search( 'pm' ) !== -1 ) && Number( tokens[0] ) < 12 ) + tokens[0] = Number( tokens[0] ) + 12; + + // We use a random date, because we only care about time. + var date = new Date( 2019, 7, 12, tokens[0], tokens[1], tokens[2] ); + var ret; + switch( ptf ) + { + case 0: + ret = util.printd( "hh:MM", date ); + break; + case 1: + ret = util.printd( "h:MM ap", date ); + break; + case 2: + ret = util.printd( "hh:MM:ss", date ); + break; + case 3: + ret = util.printd( "h:MM:ss ap", date ); + break; + } + event.value = ret; +} + +/** AFTime_Keystroke + * + * Checks if the string in event.value is valid. Not used. + */ +function AFTime_Keystroke( ptf ) +{ + return; +}