You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ms...@apache.org on 2015/01/13 20:59:34 UTC

svn commit: r1651462 - in /pdfbox/trunk/pdfbox/src: main/java/org/apache/pdfbox/pdmodel/interactive/form/ test/java/org/apache/pdfbox/pdmodel/interactive/form/

Author: msahyoun
Date: Tue Jan 13 19:59:34 2015
New Revision: 1651462

URL: http://svn.apache.org/r1651462
Log:
PDFBOX-2516 support export value and display value for choice field options

Added:
    pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestListBox.java   (with props)
Modified:
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java
    pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java?rev=1651462&r1=1651461&r2=1651462&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDChoice.java Tue Jan 13 19:59:34 2015
@@ -43,6 +43,16 @@ public abstract class PDChoice extends P
     private static final int FLAG_MULTI_SELECT = 1 << 21;
     private static final int FLAG_DO_NOT_SPELL_CHECK = 1 << 22;
     private static final int FLAG_COMMIT_ON_SEL_CHANGE = 1 << 26;
+    
+    /**
+     * @see PDFieldTreeNode#PDFieldTreeNode(PDAcroForm)
+     *
+     * @param theAcroForm The acroform.
+     */
+    protected PDChoice(PDAcroForm theAcroForm)
+    {
+        super( theAcroForm );
+    }
 
     /**
      * Constructor.
@@ -58,35 +68,75 @@ public abstract class PDChoice extends P
 
     /**
      * This will get the option values "Opt".
-     *
-     * @return COSArray containing all options.
+     * 
+     * <p>
+     * For a choice field the options array can either be an array
+     * of text strings or an array of a two-element arrays.<br/>
+     * The method always only returns either the text strings or,
+     * in case of two-element arrays, an array of the first element of 
+     * the two-element arrays
+     * </p>   
+     * <p>
+     * Use {@link #getOptionsExportValues()} and {@link #getOptionsDisplayValues()}
+     * to get the entries of two-element arrays.
+     * </p>
+     * 
+     * @return List containing the export values.
      */
     public List<String> getOptions()
     {
-        COSBase value = getDictionary().getDictionaryObject(COSName.V);
-        if (value instanceof COSString)
+        COSBase values = getDictionary().getDictionaryObject(COSName.OPT);
+        if (values instanceof COSString)
         {
             List<String> array = new ArrayList<String>();
-            array.add(((COSString) value).getString());
+            array.add(((COSString) values).getString());
             return array;
         }
-        else if (value instanceof COSArray)
+        else if (values instanceof COSArray)
         {
-            return COSArrayList.convertCOSStringCOSArrayToList((COSArray)value);
+            // test if there is a single text or a two-element array 
+            COSBase entry = ((COSArray) values).get(0);
+            if (entry instanceof COSString)
+            {
+                return COSArrayList.convertCOSStringCOSArrayToList((COSArray)values);
+            } 
+            else
+            {
+                List<String> exportValues = new ArrayList<String>();
+                int numItems = ((COSArray) values).size();
+                for (int i=0;i<numItems;i++)
+                {
+                    COSArray pair = (COSArray) ((COSArray) values).get(i);
+                    COSString displayValue = (COSString) pair.get(0);
+                    exportValues.add(displayValue.getString());
+                }
+                return exportValues;
+            }
+            
         }
         return Collections.<String>emptyList();
     }
 
     /**
-     * This will set the options.
+     * This will set the display values - the 'Opt' key.
+     * 
+     * <p>
+     * The Opt array specifies the list of options in the choice field either
+     * as an array of text strings representing the display value 
+     * or as an array of a two-element array where the
+     * first element is the export value and the second the display value.
+     * </p>
+     * <p>
+     * To set both the export and the display value use {@link #setOptions(List, List)}
+     * </p> 
      *
-     * @param values COSArray containing all possible options.
+     * @param displayValues List containing all possible options.
      */
-    public void setOptions(List<String> values)
+    public void setOptions(List<String> displayValues)
     {
-        if (values != null)
+        if (displayValues != null)
         {
-            getDictionary().setItem(COSName.OPT, COSArrayList.convertStringListToCOSStringCOSArray(values));
+            getDictionary().setItem(COSName.OPT, COSArrayList.convertStringListToCOSStringCOSArray(displayValues));
         }
         else
         {
@@ -95,6 +145,116 @@ public abstract class PDChoice extends P
     }
 
     /**
+     * This will set the display and export values - the 'Opt' key.
+     *
+     * <p>
+     * This will set both, the export value and the display value
+     * of the choice field. If either one of the parameters is null or an 
+     * empty list is supplied the options will
+     * be removed.
+     * </p>
+     * <p>
+     * An {@link IllegalArgumentException} will be thrown if the
+     * number of items in the list differ.
+     * </p>
+     *
+     * @see #setOptions(List)
+     * @param exportValues List containing all possible export values.
+     * @param displayValues List containing all possible display values.
+     */
+    public void setOptions(List<String> exportValues, List<String> displayValues)
+    {
+        if (exportValues == null || displayValues == null || exportValues.size() == 0 || displayValues.size() == 0)
+        {
+            getDictionary().removeItem(COSName.OPT);
+        }
+        else if (exportValues != null && displayValues != null && exportValues.size() > 0 && displayValues.size() > 0) 
+        {
+            if (exportValues.size() != displayValues.size())
+            {
+                throw new IllegalArgumentException(
+                        "The number of entries for exportValue and displayValue shall be the same.");
+            }
+            else
+            {
+                COSArray options = new COSArray();
+                for (int i = 0; i<exportValues.size(); i++)
+                {
+                    COSArray entry = new COSArray();
+                    entry.add(new COSString(exportValues.get(i)));
+                    entry.add(new COSString(displayValues.get(i)));
+                    options.add(entry);
+                }
+                getDictionary().setItem(COSName.OPT, options);
+            }
+        }
+    }
+
+    /**
+     * This will get the display values from the options.
+     * 
+     * <p>
+     * For options with an array of text strings the display value and export value
+     * are the same.<br/>
+     * For options with an array of two-element arrays the display value is the 
+     * second entry in the two-element array.
+     * </p>
+     * 
+     * @return List containing all the display values.
+     */
+    public List<String> getOptionsDisplayValues()
+    {
+        COSBase values = getDictionary().getDictionaryObject(COSName.OPT);
+        if (values instanceof COSString)
+        {
+            List<String> array = new ArrayList<String>();
+            array.add(((COSString) values).getString());
+            return array;
+        }
+        else if (values instanceof COSArray)
+        {
+            // test if there is a single text or a two-element array 
+            COSBase entry = ((COSArray) values).get(0);
+            if (entry instanceof COSString)
+            {
+                return COSArrayList.convertCOSStringCOSArrayToList((COSArray)values);
+            } 
+            else
+            {
+                List<String> displayValues = new ArrayList<String>();
+                int numItems = ((COSArray) values).size();
+                for (int i=0;i<numItems;i++)
+                {
+                    COSArray pair = (COSArray) ((COSArray) values).get(i);
+                    COSString displayValue = (COSString) pair.get(1);
+                    displayValues.add(displayValue.getString());
+                }
+                return displayValues;
+            }
+            
+        }
+        return Collections.<String>emptyList();
+    }
+
+    /**
+     * This will get the export values from the options.
+     * 
+     * <p>
+     * For options with an array of text strings the display value and export value
+     * are the same.<br/>
+     * For options with an array of two-element arrays the export value is the 
+     * first entry in the two-element array.
+     * </p>
+     *
+     * @return List containing all export values.
+     */
+    public List<String> getOptionsExportValues()
+    {
+        return getOptions();
+    }
+    
+    
+    /**
      * This will get the indices of the selected options "I".
      *
      * @return COSArray containing the indices of all selected options.
@@ -316,7 +476,7 @@ public abstract class PDChoice extends P
         return indexSelected;
     }
 
-    // TODO the implementation below is not inline 
+    // TODO the implementation below is not in line 
     // with the specification nor does it allow multiple selections
     // deactivating for now as it's not part of the public API
     //

Modified: pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java?rev=1651462&r1=1651461&r2=1651462&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java (original)
+++ pdfbox/trunk/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/interactive/form/PDListBox.java Tue Jan 13 19:59:34 2015
@@ -26,6 +26,17 @@ import org.apache.pdfbox.cos.COSName;
  */
 public final class PDListBox extends PDChoice
 {
+    
+    /**
+     * @see PDFieldTreeNode#PDFieldTreeNode(PDAcroForm)
+     *
+     * @param theAcroForm The acroform.
+     */
+    protected PDListBox(PDAcroForm theAcroForm)
+    {
+        super( theAcroForm );
+    }
+    
     /**
      * Constructor.
      * 

Added: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestListBox.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestListBox.java?rev=1651462&view=auto
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestListBox.java (added)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestListBox.java Tue Jan 13 19:59:34 2015
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.pdfbox.pdmodel.interactive.form;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.apache.pdfbox.cos.COSArray;
+import org.apache.pdfbox.cos.COSName;
+import org.apache.pdfbox.pdmodel.PDDocument;
+
+/**
+ * This will test the functionality of choice fields in PDFBox.
+ *
+ * @author Maruan Sahyoun
+ */
+public class TestListBox extends TestCase
+{
+    
+    /**
+     * Constructor.
+     *
+     * @param name The name of the test to run.
+     */
+    public TestListBox( String name )
+    {
+        super( name );
+    }
+
+    /**
+     * This will get the suite of test that this class holds.
+     *
+     * @return All of the tests that this class holds.
+     */
+    public static Test suite()
+    {
+        return new TestSuite( TestListBox.class );
+    }
+
+    /**
+     * infamous main method.
+     *
+     * @param args The command line arguments.
+     */
+    public static void main( String[] args )
+    {
+        String[] arg = {TestListBox.class.getName() };
+        junit.textui.TestRunner.main( arg );
+    }
+
+    /**
+     * This will test the radio button PDModel.
+     *
+     * @throws IOException If there is an error creating the field.
+     */
+    public void testChoicePDModel() throws IOException
+    {
+        PDDocument doc = null;
+        try
+        {
+            doc = new PDDocument();
+            PDAcroForm form = new PDAcroForm( doc );
+            PDChoice choice = new PDListBox(form);
+            
+            // test that there are no nulls returned for an empty field
+            // only specific methods are tested here
+            // assertNotNull(choice.getDefaultValue());
+            assertNotNull(choice.getOptions());
+            assertNotNull(choice.getValue());
+            
+            // define display and export values as the choice field can hold a pair
+            List<String> exportValues = new ArrayList<String>();
+            exportValues.add("export01");
+            exportValues.add("export02");
+
+            List<String> displayValues = new ArrayList<String>();
+            displayValues.add("display01");
+            displayValues.add("display02");
+            
+            // test with exportValue being set
+
+            // setting/getting option values - the dictionaries Opt entry
+            choice.setOptions(exportValues);
+            assertEquals(exportValues,choice.getOptionsDisplayValues());
+            assertEquals(exportValues,choice.getOptionsExportValues());
+
+            COSArray optItem = (COSArray) choice.getDictionary().getItem(COSName.OPT);
+            
+            // assert that the values have been correctly set
+            assertNotNull(choice.getDictionary().getItem(COSName.OPT));
+            assertEquals(optItem.size(),2);
+            assertEquals(exportValues.get(0), optItem.getString(0));
+            
+            // assert that the values can be retrieved correctly
+            List<String> retrievedOptions = choice.getOptions();
+            assertEquals(retrievedOptions.size(),2);
+            assertEquals(retrievedOptions, exportValues);
+
+            // assert that the Opt entry is removed
+            choice.setOptions(null);
+            assertNull(choice.getDictionary().getItem(COSName.OPT));
+            // if there is no Opt entry an empty List shall be returned
+            assertEquals(choice.getOptions(), Collections.<String>emptyList());
+            
+            // test with exportValue and displayValue being set
+            
+            // setting display and export value
+            choice.setOptions(exportValues, displayValues);
+            assertEquals(displayValues,choice.getOptionsDisplayValues());
+            assertEquals(exportValues,choice.getOptionsExportValues());
+            
+            // assert that the Opt entry is removed
+            choice.setOptions(null, displayValues);
+            assertNull(choice.getDictionary().getItem(COSName.OPT));
+            // if there is no Opt entry an empty List shall be returned
+            assertEquals(choice.getOptions(), Collections.<String>emptyList());
+            assertEquals(choice.getOptionsDisplayValues(), Collections.<String>emptyList());
+            assertEquals(choice.getOptionsExportValues(), Collections.<String>emptyList());
+            
+            // test that an IllegalArgumentException is thrown when export and display 
+            // value lists have different sizes
+            exportValues.remove(1);
+            
+            try
+            {
+                choice.setOptions(exportValues, displayValues);
+                fail( "Missing exception" );
+            }
+            catch( IllegalArgumentException e )
+            {
+                assertEquals( 
+                        "The number of entries for exportValue and displayValue shall be the same.",
+                        e.getMessage() );
+            }
+        }
+        finally
+        {
+            if( doc != null )
+            {
+                doc.close();
+            }
+        }
+    }
+}
\ No newline at end of file

Propchange: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestListBox.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/pdmodel/interactive/form/TestListBox.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain