diff --git a/autotests/CMakeLists.txt b/autotests/CMakeLists.txt index d40d56650..fe161bd77 100644 --- a/autotests/CMakeLists.txt +++ b/autotests/CMakeLists.txt @@ -1,98 +1,99 @@ 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/formattest.cpp b/autotests/formattest.cpp index e5b8c5813..525f24abd 100644 --- a/autotests/formattest.cpp +++ b/autotests/formattest.cpp @@ -1,146 +1,220 @@ /*************************************************************************** * 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(); + void testSpecialFormat(); 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::testSpecialFormat() +{ + Okular::FormFieldText *fft = reinterpret_cast< Okular::FormFieldText * >( m_fields[ QStringLiteral( "CEP" ) ] ); + + // This field will just become itself, so we test only if keystroke worked. + fft->setText( QStringLiteral( "12345" ) ); + bool ok = false; + m_document->processKeystrokeAction( fft->additionalAction( Okular::FormField::FieldModified ), fft, ok ); + + QCOMPARE( true, ok ); + + fft->setText( QStringLiteral( "123456" ) ); + ok = false; + m_document->processKeystrokeAction( fft->additionalAction( Okular::FormField::FieldModified ), fft, ok ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( false, ok ); + + fft = reinterpret_cast< Okular::FormFieldText * >( m_fields[ QStringLiteral( "8Digits" ) ] ); + + fft->setText( QStringLiteral( "123456789" ) ); + ok = false; + m_document->processKeystrokeAction( fft->additionalAction( Okular::FormField::FieldModified ), fft, ok ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( true, ok ); + QCOMPARE( m_formattedText, QStringLiteral( "12345-6789" ) ); + + fft->setText( QStringLiteral( "1234567890" ) ); + ok = false; + m_document->processKeystrokeAction( fft->additionalAction( Okular::FormField::FieldModified ), fft, ok ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( false, ok ); + QCOMPARE( m_formattedText, QStringLiteral( "12345-6789" ) ); + + fft = reinterpret_cast< Okular::FormFieldText * >( m_fields[ QStringLiteral( "telefone" ) ] ); + + fft->setText( QStringLiteral( "1234567890" ) ); + ok = false; + m_document->processKeystrokeAction( fft->additionalAction( Okular::FormField::FieldModified ), fft, ok ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( true, ok ); + QCOMPARE( m_formattedText, QStringLiteral("(123) 456-7890" ) ); + + fft->setText( QStringLiteral( "12345678900" ) ); + ok = false; + m_document->processKeystrokeAction( fft->additionalAction( Okular::FormField::FieldModified ), fft, ok ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( false, ok ); + QCOMPARE( m_formattedText, QStringLiteral("(123) 456-7890" ) ); + + fft = reinterpret_cast< Okular::FormFieldText * >( m_fields[ QStringLiteral( "CPF" ) ] ); + + fft->setText( QStringLiteral( "123456789" ) ); + ok = false; + m_document->processKeystrokeAction( fft->additionalAction( Okular::FormField::FieldModified ), fft, ok ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( true, ok ); + QCOMPARE( m_formattedText, QStringLiteral( "123-45-6789" ) ); + + fft->setText( QStringLiteral( "1234567890" ) ); + ok = false; + m_document->processKeystrokeAction( fft->additionalAction( Okular::FormField::FieldModified ), fft, ok ); + m_document->processFormatAction( fft->additionalAction( Okular::FormField::FormatField ), fft ); + + QCOMPARE( false, ok ); + QCOMPARE( m_formattedText, QStringLiteral( "123-45-6789" ) ); +} + 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 a5dcb3904..878ab49aa 100644 --- a/core/script/builtin.js +++ b/core/script/builtin.js @@ -1,158 +1,247 @@ /*************************************************************************** * 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; } + +/** AFSpecial_Format + * psf is the type of formatting to use: + * 0 = zip code + * 1 = zip + 4 + * 2 = phone + * 3 = SSN + * + * These are all in the US format. +*/ +function AFSpecial_Format( psf ) +{ + if( !event.value || psf == 0 ) + { + return; + } + + var ret = event.value; + + if( psf === 1 ) + ret = ret.substr( 0, 5 ) + '-' + ret.substr( 5, 4 ); + + else if( psf === 2 ) + ret = '(' + ret.substr( 0, 3 ) + ') ' + ret.substr( 3, 3 ) + '-' + ret.substr( 6, 4 ); + + else if( psf === 3 ) + ret = ret.substr( 0, 3 ) + '-' + ret.substr( 3, 2 ) + '-' + ret.substr( 5, 4 ); + + event.value = ret; +} + +/** AFSpecial_Keystroke + * + * Checks if the String in event.value is valid. + * + * Parameter description based on Acrobat Help: + * + * psf is the type of formatting to use: + * 0 = zip code + * 1 = zip + 4 + * 2 = phone + * 3 = SSN + * + * These are all in the US format. We check to see if only numbers are inserted and the length of the string. +*/ +function AFSpecial_Keystroke( psf ) +{ + if ( !event.value ) + { + return; + } + + var str = event.value; + if( psf === 0 ) + { + if( str.length > 5 ) + { + event.rc = false; + return; + } + } + + else if( psf === 1 || psf === 3 ) + { + if( str.length > 9 ) + { + event.rc = false; + return; + } + } + + else if( psf === 2 ) + { + if( str.length > 10 ) + { + event.rc = false; + return; + } + } + + for( i = 0 ; i < str.length ; ++i ) + { + if( !( str[i] <= '9' && str[i] >= '0' ) ) + { + event.rc = false; + return; + } + } +}