diff options
-rw-r--r-- | langs/cpp/tools.tpl | 223 | ||||
-rw-r--r-- | src/org/libreoffice/tools/tests/CppToolsTemplateTest.java | 269 | ||||
-rw-r--r-- | src/org/libreoffice/tools/tests/TypeManagerTest.java | 2 | ||||
-rw-r--r-- | src/org/libreoffice/tools/types/TypeManager.java | 119 |
4 files changed, 475 insertions, 138 deletions
diff --git a/langs/cpp/tools.tpl b/langs/cpp/tools.tpl index a0df9f9..0a89664 100644 --- a/langs/cpp/tools.tpl +++ b/langs/cpp/tools.tpl @@ -1,5 +1,9 @@ <#function scopedCppName type shortname=false> - <#local name = "::" + type?replace( ".", "::" )> + <#local name = ""> + <#if !type?starts_with( "::" )> + <#local name = "::"> + </#if> + <#local name = name + type?replace( ".", "::" )> <#if shortname> <#local name = name?replace( "::com::sun::star", "css" )> </#if> @@ -49,57 +53,68 @@ <#return flags> </#function> -<#function cppType unotype> - <#local cpp = unotype> - <#if unotype?is_string > - <#-- Handle UNO simple types --> - <#if unotype == "string"> - <#local cpp = "::rtl::OUString"> - <#elseif unotype == "char"> - <#local cpp = "::sal_Unicode"> - <#elseif unotype == "any"> - <#local cpp = "::com::sun::star::uno::Any"> - <#elseif unotype == "type"> - <#local cpp = "::com::sun::star::uno::Type"> - <#elseif unotype == "boolean"> - <#local cpp = "::sal_Bool"> - <#elseif unotype == "byte"> - <#local cpp = "::sal_Int8"> - <#elseif unotype == "short"> - <#local cpp = "::sal_Int16"> - <#elseif unotype == "unsigned short"> - <#local cpp = "::sal_uInt16"> - <#elseif unotype == "long"> - <#local cpp = "::sal_Int32"> - <#elseif unotype == "unsigned long"> - <#local cpp = "::sal_uInt32"> - <#elseif unotype == "hyper"> - <#local cpp = "::sal_Int64"> - <#elseif unotype == "unsigned hyper"> - <#local cpp = "::sal_uInt64"> - </#if> - <#elseif unotype?is_hash> - <#-- Handle UNO complex types --> - <#local cpp = ""> - <#local levels = (unotype["nested_levels"] - 1)> - <#if (levels > 0)> - <#list 0..levels as i> - <#local cpp = cpp + "::com::sun::star::uno::Sequence< "> - </#list> - </#if> - <#if unotype["type"] == "interface"> - <#local cpp = cpp + "::com::sun::star::uno::Reference< " + scopedCppName( unotype["name"] ) + " >"> - </#if> - <#if (levels > 0)> - <#list 0..levels as i> - <#local cpp = cpp + " >"> - </#list> +<#function cppType unotype shortname=false> + <#local cpp = unotype["name"]> + + <#-- Remove UNO sequence markers as we have the nested levels --> + <#local cpp = cpp?replace( "[]", "" )> + + <#if unotype["type"] == "simple" > + <#if ( cpp != "void" ) && ( cpp != "double" ) && ( cpp != "float" )> + <#local cpp = cpp?replace( "string", "::rtl::OUString" )> + <#local cpp = cpp?replace( "char", "::sal_Unicode" )> + <#local cpp = cpp?replace( "any", "::com::sun::star::uno::Any" )> + <#local cpp = cpp?replace( "type", "::com::sun::star::uno::Type" )> + <#local cpp = cpp?replace( "boolean", "::sal_Bool" )> + <#local cpp = cpp?replace( "byte", "::sal_Int8" )> + <#local cpp = cpp?replace( "unsigned short", "::sal_uInt16" )> + <#local cpp = cpp?replace( "short", "::sal_Int16" )> + <#local cpp = cpp?replace( "unsigned long", "::sal_uInt32" )> + <#local cpp = cpp?replace( "long", "::sal_Int32" )> + <#local cpp = cpp?replace( "unsigned hyper", "::sal_uInt64" )> + <#local cpp = cpp?replace( "hyper", "::sal_Int64" )> + + <#local cpp = scopedCppName( cpp, shortname )> </#if> + <#elseif unotype["type"] == "interface"> + <#local cpp = "::com::sun::star::uno::Reference< " + scopedCppName( cpp ) + " >"> + </#if> + + <#local levels = (unotype["nested_levels"] - 1)> + <#if (levels > 0)> + <#list 0..levels as i> + <#local cpp = "::com::sun::star::uno::Sequence< " + cpp + " >"> + </#list> + </#if> + + <#if shortname> + <#local name = name?replace( "::com::sun::star", "css" )> </#if> <#return cpp> </#function> -<#function printFieldSignature field setter> +<#function defaultValue unotype> + <#local value = ""> + <#if unotype["type"] == "simple"> + <#local value = "0"> + <#if unotype["name"] == "boolean"> + <#local value = "sal_False"> + <#elseif unotype["name"] == "string"> + <#local value = "::rtl::OUString()"> + <#elseif unotype["name"] == "double" || unotype["name"] == "float"> + <#local value = "0.0"> + <#elseif unotype["name"] == "void"> + <#local value = cppType( unotype )> + <#elseif unotype["name"] == "any" || unotype["name"] == "type"> + <#local value = cppType( unotype ) + "()"> + </#if> + <#elseif unotype["type"] == "interface"> + <#local value = cppType( unotype ) + "()"> + </#if> + <#return value> +</#function> + +<#function printFieldSignature field setter classname = ""> <#if setter> <#local return_type = "void"> <#local name_prefix = "set"> @@ -110,41 +125,111 @@ <#local args = "" > </#if> - <#local result = return_type + " SAL_CALL " + name_prefix + field["name"] + "(" + args + ")" > - <#local result = result + " throw (" + printExceptions( field["get_exceptions"] ) +")" > + <#local result = return_type + " SAL_CALL " + classname + name_prefix + field["name"] + "(" + args + ")" > + <#local result = result + " throw ("> + <#if setter> + <#local result = result + printExceptions( field["set_exceptions"] ) +")" > + <#else> + <#local result = result + printExceptions( field["get_exceptions"] ) +")" > + </#if> <#return result> </#function> -<#macro printField field print_body> - <#if !print_body>virtual </#if>${printFieldSignature( field, false )}<#if !print_body>;<#else> +<#macro printSetPropertyMixinBody field> + <#if field["bound"]>BoundListeners l; + </#if><#if field["set_exceptions"]?seq_contains("com.sun.star.beans.PropertyVetoException")>css::Any v; + <#if field["type"]["name"]?contains("com.sun.star.beans.Optional")>if ( the_value.IsPresent ) { - // TODO Implement the body here - } - </#if> - -<#if !field["readonly"]><#if !print_body>virtual </#if>${printFieldSignature( field, true )}<#if !print_body>;<#else> + v <<= the_value.Value; + }<#else>v <<= the_value.Value;</#if> + prepareSet( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("${field["name"]}")), + css::uno::Any(), v, <#if field["bound"]>&l<#else>NULL</#if>); + <#else> + prepareSet( + rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("${field["name"]}")), + css::uno::Any(), css::uno::Any(), <#if field["bound"]>&l<#else>NULL</#if>); + </#if> { - // TODO Implement the body here - } -</#if></#if> + osl::MutexGuard g(m_aMutex); + m_${field["name"]} = the_value; + }<#if !field["bound"]><#return></#if> + <#if field["bound"]>l.notify();<#return></#if> </#macro> -<#macro printMethods intf> - // TODO -<#assign generated = generated + ":" + intf["name"] + ":"> -// TODO Continue -<#if all_methods > -<#list intf["super_types"] as super> -<@printMethods super/> -</#list> -<#if intf["fields"]?size > 0 || intf["methods"]?size > 0> - // ${intf["name"]?replace( ".", ":" )}: +<#macro printField field print_body><#local scopedname = ""> +<#if !print_body>virtual <#else><#local scopedname = classname() + "::"></#if>${printFieldSignature( field, false, scopedname )}<#if !print_body>;<#else> +{ + <#if (propertyHelper?length > 0)>osl::MutexGuard g(m_aMutex); + </#if>return m_${field["name"]}; +} </#if> + +<#if !field["readonly"]><#if !print_body>virtual </#if>${printFieldSignature( field, true, scopedname )}<#if !print_body>;<#else> +{ +<#if (propertyHelper?length > 0)><@printSetPropertyMixinBody field /><#else> m_${field["name"]} = the_value;</#if> +} +</#if></#if> +</#macro> + +<#function getRef unotype> + <#local ref = ""> + <#if unotype["name"] == "string" || unotype["name"] == "any" || unotype["name"] == "type" + || (unotype["nested_levels"] > 0) || unotype["type"] == "interface"> + <#local ref = "&"> + </#if> + <#return ref> +</#function> + +<#-- + Returns the arguments list for the given method + * args: the list of parameters to print + --> +<#function printMethodParams args> + <#local result = ""> + <#list args as arg> + <#if !arg["flags"]?contains( "out" )> + <#local result = result + "const "> + </#if> + <#local result = result + cppType( arg["type"] ) + getRef( arg["type"]) + " " + arg["name"]> + <#if arg_has_next><#local result = result + ", "></#if> + </#list> + <#return result> +</#function> + +<#-- + Returns the interface method signature. + * method: the method object for which to print the signature + * classname: is used when printing the implementation signature + --> +<#function printMethodSignature method classname = ""> + <#local sig = cppType(method["return_type"]) + " SAL_CALL " + method["name"] + "(" + printMethodParams(method["parameters"]) + ")"> + <#local sig = sig + " throw (" + printExceptions( method["exceptions"] ) + ")"> + <#return sig> +</#function> + +<#macro printMethod method print_body> +<#if !print_body>virtual </#if>${printMethodSignature(method)}<#if !print_body>;<#else> +{ + <#if method["return_type"] != "void">// TODO: Exchange the default return implementation for "${method["name"]}"!!! + // Exchange the default return implementation. + // NOTE: Default initialized polymorphic structs can cause problems because of + // missing default initialization of primitive types of some C++ compilers or + // different Any initialization in Java and C++ polymorphic structs. + return ${defaultValue( method["return_type"] )};<#else>// TODO: Insert your implementation for "${method["name"]}" here.</#if> +} </#if> +</#macro> +<#macro printMethods intf><#assign generated = generated + ":" + intf["name"] + ":"> +<#if all_methods ><#list intf["super_types"] as super><@printMethods super/></#list> +<#if (intf["fields"]?size > 0) || (intf["methods"]?size > 0)> // ${intf["name"]?replace( ".", ":" )}:</#if></#if> <#list intf["fields"] as field> <@printField(field, false)/> </#list> +<#list intf["methods"] as method> +<@printMethod(method, false)/> +</#list> </#macro> <#macro printMethodsBodies intf> diff --git a/src/org/libreoffice/tools/tests/CppToolsTemplateTest.java b/src/org/libreoffice/tools/tests/CppToolsTemplateTest.java index f2305b4..110eae0 100644 --- a/src/org/libreoffice/tools/tests/CppToolsTemplateTest.java +++ b/src/org/libreoffice/tools/tests/CppToolsTemplateTest.java @@ -2,6 +2,7 @@ package org.libreoffice.tools.tests; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; @@ -27,8 +28,16 @@ import freemarker.template.TemplateException; public class CppToolsTemplateTest { + private static final String TEST_IMPLNAME = "some.test.Type"; + private static final String TEST_SIMPLE_IMPLNAME = "Type"; + private static final String EXPECTED_CLASSNAME = "Type"; + private static final String EXPECTED_COMP_NAMESPACE = "::some::test::comp_Type"; + private static final String EXPECTED_NAMESPACE = "::some::test::Type"; + private static final String[] TEST_EXCEPTIONS = new String[]{ "some.type.Exception1", "some.type.Exception2" }; + private static final String[] TEST_VETOABLE_EXCEPTIONS = new String[]{ "some.type.Exception1", "com.sun.star.beans.PropertyVetoException" }; private static final String EXPECTED_EXCEPTIONS = "::com::sun::star::uno::RuntimeException, ::some::type::Exception1, ::some::type::Exception2"; + private static final String EXPECTED_VETOABLE_EXCEPTIONS = "::com::sun::star::uno::RuntimeException, ::some::type::Exception1, ::com::sun::star::beans::PropertyVetoException"; private static final String[] TEST_EXCEPTIONS_EMPTY = new String[]{ }; private static final String EXPECTED_EXCEPTIONS_EMPTY = "::com::sun::star::uno::RuntimeException"; @@ -72,33 +81,33 @@ public class CppToolsTemplateTest { @Test public void classnameFqdnTest( ) throws IOException, TemplateException { HashMap<String, Object> model = new HashMap<String, Object>(); - model.put( "implname", "some.test.Type" ); + model.put( "implname", TEST_IMPLNAME ); String result = processTemplate( "${classname()}", model ); - assertEquals( "Wrong classname", "Type", result ); + assertEquals( "Wrong classname", EXPECTED_CLASSNAME, result ); } @Test public void classnameSimpleTest( ) throws IOException, TemplateException { HashMap<String, Object> model = new HashMap<String, Object>(); - model.put( "implname", "Type" ); + model.put( "implname", TEST_SIMPLE_IMPLNAME ); String result = processTemplate( "${classname()}", model ); - assertEquals( "Wrong classname", "Type", result ); + assertEquals( "Wrong classname", EXPECTED_CLASSNAME, result ); } @Test public void generateNamespaceFqdnNoPrefixTest( ) throws IOException, TemplateException { HashMap<String, Object> model = new HashMap<String, Object>(); - model.put( "implname", "some.test.Type" ); + model.put( "implname", TEST_IMPLNAME ); String result = processTemplate( "${generateNamespace()}", model ); - assertEquals( "Wrong classname", "::some::test::Type", result ); + assertEquals( "Wrong namespace", EXPECTED_NAMESPACE, result ); } @Test public void generateNamespaceFqdnPrefixTest( ) throws IOException, TemplateException { HashMap<String, Object> model = new HashMap<String, Object>(); - model.put( "implname", "some.test.Type" ); + model.put( "implname", TEST_IMPLNAME ); String result = processTemplate( "${generateNamespace( \"comp_\" )}", model ); - assertEquals( "Wrong classname", "::some::test::comp_Type", result ); + assertEquals( "Wrong namespace", EXPECTED_COMP_NAMESPACE, result ); } @Test @@ -106,7 +115,7 @@ public class CppToolsTemplateTest { HashMap<String, Object> model = new HashMap<String, Object>(); model.put( "implname", "Type" ); String result = processTemplate( "${generateNamespace()}", model ); - assertEquals( "Wrong classname", "::Type", result ); + assertEquals( "Wrong namespace", "::Type", result ); } @Test @@ -161,18 +170,18 @@ public class CppToolsTemplateTest { public void printFieldSignatureGetterTest( ) throws IOException, TemplateException { HashMap<String, Object> model = new HashMap<String, Object>(); boolean readonly = false; - model.put( "field", getTestField( readonly ) ); + model.put( "field", getTestField( readonly, false, false, false ) ); String result = processTemplate( "${printFieldSignature( field, false )}", model ); - assertEquals( getFieldGetterSignature(), result ); + assertEquals( getFieldGetterSignature( new String(), false ), result ); } @Test public void printFieldSignatureSetterReadwriteTest( ) throws IOException, TemplateException { HashMap<String, Object> model = new HashMap<String, Object>(); boolean readonly = false; - model.put( "field", getTestField( readonly ) ); + model.put( "field", getTestField( readonly, false, false, false ) ); String result = processTemplate( "${printFieldSignature( field, true )}", model ); - assertEquals( getFieldSetterSignature( readonly ), result ); + assertEquals( getFieldSetterSignature( new String(), readonly, false, false ), result ); } @Test @@ -197,11 +206,14 @@ public class CppToolsTemplateTest { Iterator<String> it = mappings.keySet().iterator(); while ( it.hasNext() ) { String unoType = it.next(); - String result = processTemplate( "${cppType( \"" + unoType + "\" )}", new HashMap<String, Object>() ); + HashMap<String, Object> model = new HashMap<String, Object>(); + model.put( "type", getTestType( unoType, TypeManager.UNO_TYPE_CLASS_SIMPLE, 0 ) ); + + String result = processTemplate( "${cppType( type )}", model ); assertEquals( "Wrong c++ type for UNO: " + unoType, mappings.get( unoType ), result ); } } - + @Test public void cppTypeInterfaceTest() throws IOException, TemplateException { @@ -223,13 +235,33 @@ public class CppToolsTemplateTest { } @Test - public void cppTypeSequenceTest() throws IOException, TemplateException { + public void cppTypeSequenceSimpleTest() throws IOException, TemplateException { // Populate the template model with a test interface type HashMap<String, Object> model = new HashMap<String, Object>(); HashMap<String, Object> type = new HashMap<String, Object>(); - type.put( TypeManager.UNO_TYPE_NAME, "some.type.XType" ); + type.put( TypeManager.UNO_TYPE_NAME, "[][]short" ); + type.put( TypeManager.UNO_NESTED_LEVELS, 2 ); + type.put( TypeManager.UNO_TYPE_CLASS, "simple" ); + + model.put( "testtype", type ); + + // Run the test + String result = processTemplate( "${cppType( testtype )}", model ); + + // Compare + assertEquals( "Wrong c++ type for sequence of simple types", "::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::sal_Int16 > >", result ); + } + + @Test + public void cppTypeSequenceInterfaceTest() throws IOException, TemplateException { + + // Populate the template model with a test interface type + HashMap<String, Object> model = new HashMap<String, Object>(); + + HashMap<String, Object> type = new HashMap<String, Object>(); + type.put( TypeManager.UNO_TYPE_NAME, "[][]some.type.XType" ); type.put( TypeManager.UNO_NESTED_LEVELS, 2 ); type.put( TypeManager.UNO_TYPE_CLASS, "interface" ); @@ -241,27 +273,216 @@ public class CppToolsTemplateTest { // Compare assertEquals( "Wrong c++ type for interfaces", "::com::sun::star::uno::Sequence< ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Reference< ::some::type::XType > > >", result ); } + + @Test + public void defaultValueSimpleTypeTest() throws IOException, TemplateException { + + HashMap<String, String> mappings = new HashMap<String, String>(); + mappings.put( "void", "void" ); + mappings.put( "boolean", "sal_False" ); + mappings.put( "byte", "0" ); + mappings.put( "short", "0" ); + mappings.put( "unsigned short", "0" ); + mappings.put( "long", "0" ); + mappings.put( "unsigned long", "0" ); + mappings.put( "hyper", "0" ); + mappings.put( "unsigned hyper", "0" ); + mappings.put( "float", "0.0" ); + mappings.put( "double", "0.0" ); + mappings.put( "char", "0" ); + mappings.put( "string", "::rtl::OUString()" ); + mappings.put( "type", "::com::sun::star::uno::Type()" ); + mappings.put( "any", "::com::sun::star::uno::Any()" ); + + Iterator<String> it = mappings.keySet().iterator(); + while ( it.hasNext() ) { + String unoType = it.next(); + HashMap<String, Object> model = new HashMap<String, Object>(); + model.put( "type", getTestType( unoType, TypeManager.UNO_TYPE_CLASS_SIMPLE, 0 ) ); + String result = processTemplate( "${defaultValue( type )}", model ); + assertEquals( "Wrong c++ default value for UNO type: " + unoType, mappings.get( unoType ), result ); + } + } + + @Test + public void defaultValueInterfaceTest() throws IOException, TemplateException { + + // Populate the template model with a test interface type + HashMap<String, Object> model = new HashMap<String, Object>(); + + HashMap<String, Object> type = new HashMap<String, Object>(); + type.put( TypeManager.UNO_TYPE_NAME, "some.type.XType" ); + type.put( TypeManager.UNO_NESTED_LEVELS, 0 ); + type.put( TypeManager.UNO_TYPE_CLASS, "interface" ); + + model.put( "testtype", type ); + + // Run the test + String result = processTemplate( "${defaultValue( testtype )}", model ); + + // Compare + assertEquals( "Wrong c++ default value for interfaces", "::com::sun::star::uno::Reference< ::some::type::XType >()", result ); + } + + @Test + public void printFieldBodyTest() throws IOException, TemplateException { + + int READONLY = 0x1; + int BOUND = 0x2; + int USEMIXIN = 0x4; + int OPTIONAL = 0x8; + int VETOABLE = 0x16; + + int flags = 0; + int allFlags = READONLY | BOUND | USEMIXIN | OPTIONAL | VETOABLE; + + while ( flags <= allFlags ) { + boolean readonly = ( flags & READONLY ) > 0; + boolean bound = ( flags & BOUND ) > 0; + boolean usemixin = ( flags & USEMIXIN ) > 0; + boolean optional = ( flags & OPTIONAL ) > 0; + boolean vetoable = ( flags & VETOABLE ) > 0; + + HashMap<String, Object> model = new HashMap<String, Object>(); + + model.put( "implname", TEST_IMPLNAME ); + model.put( "field", getTestField( readonly, bound, optional, vetoable ) ); + model.put( "propertyHelper", usemixin ? "some.helper" : new String() ); - private Object getTestField( boolean pReadonly) { + String result = processTemplate( "<@printField field true/>", model ); + + String expected = getFieldGetterSignature( EXPECTED_CLASSNAME + "::", optional ) + "\n" + getFieldGetterBody( usemixin ) + "\n"; + if ( !readonly ) { + expected += getFieldSetterSignature( EXPECTED_CLASSNAME + "::", readonly, optional, vetoable ) + "\n" + getFieldSetterBody( usemixin, bound, optional, vetoable ); + } + + String failMessage = MessageFormat.format( + "Unexpected field bodies for ( Readonly, Bound, UseMixin, Optional, Vetoable) = ( {0}, {1}, {2}, {3}, {4} ), ", + readonly, bound, usemixin, optional, vetoable ); + assertEquals( failMessage, expected, result ); + + flags++; + } + } + + @Test + public void getRefTest( ) throws IOException, TemplateException { + fail( "Not implemented" ); + } + + @Test + public void printMethodParamsTest( ) throws IOException, TemplateException { + fail( "Not implemented" ); + } + + @Test + public void printMethodSignatureTest( ) throws IOException, TemplateException { + fail( "Not implemented" ); + } + + @Test + public void printMethodTest( ) throws IOException, TemplateException { + fail( "Not implemented" ); + } + + private Object getTestType(String pName, String pTypeClass, int pLevels) { + HashMap<String, Object> model = new HashMap<String, Object>(); + + model.put( TypeManager.UNO_TYPE_NAME, pName ); + model.put( TypeManager.UNO_TYPE_CLASS, pTypeClass ); + model.put( TypeManager.UNO_NESTED_LEVELS, Integer.valueOf( pLevels ) ); + + return model; + } + + private Object getTestField( boolean pReadonly, boolean pBound, boolean pOptional, boolean pVetoable ) { HashMap<String, Object> field = new HashMap<String, Object>(); + String typeName = "string"; + if ( pOptional ) { + typeName = "com.sun.star.beans.Optional<" + typeName + ">"; + } + field.put( TypeManager.FIELD_NAME, "Foo"); - field.put( TypeManager.FIELD_TYPE, "string" ); + field.put( TypeManager.FIELD_TYPE, getTestType( typeName, TypeManager.UNO_TYPE_CLASS_SIMPLE, 0 ) ); field.put( TypeManager.FIELD_GET_EXCEPTIONS, TEST_EXCEPTIONS ); - field.put( TypeManager.FIELD_SET_EXCEPTIONS, TEST_EXCEPTIONS ); + field.put( TypeManager.FIELD_SET_EXCEPTIONS, ( pVetoable ? TEST_VETOABLE_EXCEPTIONS : TEST_EXCEPTIONS ) ); field.put( TypeManager.FIELD_READONLY, Boolean.valueOf( pReadonly ) ); + field.put( TypeManager.FIELD_BOUND, Boolean.valueOf( pBound ) ); return field; } - private Object getFieldGetterSignature() { - return "::rtl::OUString SAL_CALL getFoo() throw (" + EXPECTED_EXCEPTIONS + ")"; + private String getFieldGetterSignature( String pClassname, boolean pOptional ) { + String type = "::rtl::OUString"; + if ( pOptional ) { + type = "::com::sun::star::beans::Optional<" + type + ">"; + } + return type + " SAL_CALL " + pClassname + "getFoo() throw (" + EXPECTED_EXCEPTIONS + ")"; + } + + private String getFieldGetterBody( boolean pUseMixin ) { + StringBuffer buf = new StringBuffer(); + buf.append( "{\n" ); + if ( pUseMixin ) { + buf.append( " osl::MutexGuard g(m_aMutex);\n" ); + } + buf.append( " return m_Foo;\n" ); + buf.append( "}\n" ); + return buf.toString(); + } + + private String getFieldSetterBody( boolean pUseMixin, boolean pBound, boolean pOptional, boolean pVetoable ) { + StringBuffer buf = new StringBuffer(); + buf.append( "{\n" ); + if ( pUseMixin ) { + String listener = "NULL"; + if ( pBound ) { + buf.append( " BoundListeners l;\n" ); + listener = "&l"; + } + if ( pVetoable ) { + buf.append( " css::Any v;\n" ); + if ( pOptional ) { + buf.append( " if ( the_value.IsPresent )\n" ); + buf.append( " {\n" ); + buf.append( " v <<= the_value.Value;\n" ); + buf.append( " }\n" ); + } else { + buf.append( " v <<= the_value.Value;\n" ); + } + buf.append( " prepareSet(\n" ); + buf.append( " rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(\"Foo\")),\n"); + buf.append( " css::uno::Any(), v, " + listener + ");\n"); + } else { + buf.append( " prepareSet(\n" ); + buf.append( " rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(\"Foo\")),\n"); + buf.append( " css::uno::Any(), css::uno::Any(), " + listener + ");\n"); + } + buf.append( " {\n" ); + buf.append( " osl::MutexGuard g(m_aMutex);\n"); + buf.append( " m_Foo = the_value;\n" ); + buf.append( " }\n" ); + + if ( pBound ) { + buf.append( " l.notify();\n" ); + } + } else { + buf.append( " m_Foo = the_value;\n" ); + } + buf.append( "}\n" ); + return buf.toString(); } - private Object getFieldSetterSignature( boolean pReadonly ) { + private String getFieldSetterSignature( String pClassname, boolean pReadonly, boolean pOptional, boolean pVetoable ) { String result = new String(); if ( !pReadonly ) { - result = "void SAL_CALL setFoo(::rtl::OUString the_value) throw (" + EXPECTED_EXCEPTIONS + ")"; + String type = "::rtl::OUString"; + if ( pOptional ) { + type = "::com::sun::star::beans::Optional<" + type + ">"; + } + String exceptions = pVetoable ? EXPECTED_VETOABLE_EXCEPTIONS : EXPECTED_EXCEPTIONS; + result = "void SAL_CALL " + pClassname + "setFoo(" + type + " the_value) throw (" + exceptions + ")"; } return result; } diff --git a/src/org/libreoffice/tools/tests/TypeManagerTest.java b/src/org/libreoffice/tools/tests/TypeManagerTest.java index c9eb151..6bda834 100644 --- a/src/org/libreoffice/tools/tests/TypeManagerTest.java +++ b/src/org/libreoffice/tools/tests/TypeManagerTest.java @@ -109,11 +109,13 @@ public class TypeManagerTest { assertNotNull( "Field missing", roField ); assertNotNull( "missing type", roField.get( TypeManager.FIELD_TYPE ) ); assertTrue( "Should be readonly", ((Boolean)roField.get( TypeManager.FIELD_READONLY ) ).booleanValue() ); + assertFalse( "Shouldn't be bound", ((Boolean)roField.get( TypeManager.FIELD_BOUND ) ).booleanValue() ); Map<?, ?> simpleField = getField( fields, READWRITE_FIELD ); assertNotNull( "Field missing", simpleField ); assertNotNull( "missing type", simpleField.get( TypeManager.FIELD_TYPE ) ); assertFalse( "Shouldn't be readonly", ((Boolean)simpleField.get( TypeManager.FIELD_READONLY ) ).booleanValue() ); + assertFalse( "Shouldn't be bound", ((Boolean)roField.get( TypeManager.FIELD_BOUND ) ).booleanValue() ); Map<?, ?> excepField = getField( fields, SETEXCEPTION_FIELD ); assertNotNull( "Field missing", excepField ); diff --git a/src/org/libreoffice/tools/types/TypeManager.java b/src/org/libreoffice/tools/types/TypeManager.java index 89a1726..cd53b45 100644 --- a/src/org/libreoffice/tools/types/TypeManager.java +++ b/src/org/libreoffice/tools/types/TypeManager.java @@ -47,6 +47,7 @@ public class TypeManager { public static final String FIELD_NAME = "name"; public static final String FIELD_TYPE = "type"; public static final String FIELD_READONLY = "readonly"; + public static final String FIELD_BOUND = "bound"; public static final String FIELD_GET_EXCEPTIONS = "get_exceptions"; public static final String FIELD_SET_EXCEPTIONS = "set_exceptions"; @@ -54,6 +55,10 @@ public class TypeManager { public static final String UNO_TYPE_NAME = "name"; public static final String UNO_TYPE_CLASS = "type"; public static final String UNO_NESTED_LEVELS = "nested_levels"; + + public static final String UNO_TYPE_CLASS_SIMPLE = "simple"; + + public static final String UNO_TYPE_CLASS_INTERFACE = "interface"; private String mInstallDir; @@ -317,21 +322,11 @@ public class TypeManager { * <tr><th>Name</th> <th>Type</th> <th>Description</th></tr> * <tr><td>name</td><td>String</td><td>the name of the interface</td></tr> * <tr><td>super_type</td><td>Sequence of interfaces</td><td>the base interfaces</td></tr> - * <tr><td>fields</td><td>Sequence of fields</td><td>the interface fields model</td></tr> + * <tr><td>fields</td><td>Sequence of attributes</td><td>the interface attributes model</td></tr> * <tr><td>methods</td><td>Sequence of methods</td><td>the interface methods model</td></tr> * <tr><td>TODO name</td><td>type</td><td>description</td></tr> * </table> * - * Field object: - * <table border="1"> - * <tr><th>Name</th> <th>Type</th> <th>Description</th></tr> - * <tr><td>name</td><td>String</td><td>the name of the field</td></tr> - * <tr><td>type</td><td>Map</td><td>the UNO type of the field</td></tr> - * <tr><td>get_exception</td><td>sequence of string</td><td>the names of the get exceptions or an empty list</td></tr> - * <tr><td>set_exception</td><td>sequence of string</td><td>the names of the set exceptions or an empty list</td></tr> - * <tr><td>TODO name</td><td>type</td><td>description</td></tr> - * </table> - * * @param pIntf the name of the interface for which to get a model. * * @return the interface model or <code>null</code> @@ -361,8 +356,6 @@ public class TypeManager { // Fields and methods for (XInterfaceMemberTypeDescription member : xIface2.getMembers() ) { - HashMap<String, Object> memberModel = new HashMap<String, Object>(); - XInterfaceAttributeTypeDescription2 attribute = UnoRuntime.queryInterface( XInterfaceAttributeTypeDescription2.class, member ); XInterfaceMethodTypeDescription method = UnoRuntime.queryInterface( @@ -370,30 +363,12 @@ public class TypeManager { if ( attribute != null ) { // Handle the attribute here - memberModel.put( FIELD_NAME, attribute.getMemberName() ); - memberModel.put( FIELD_TYPE, getTypeModel( attribute.getType() ) ); - memberModel.put( FIELD_READONLY, Boolean.valueOf( attribute.isReadOnly() ) ); - - ArrayList<String> getExceptions = new ArrayList<String>(); - XCompoundTypeDescription[] getExpt = attribute.getGetExceptions(); - for (XCompoundTypeDescription exceptionType : getExpt) { - getExceptions.add( exceptionType.getName() ); - } - memberModel.put( FIELD_GET_EXCEPTIONS, getExceptions ); - - ArrayList<String> setExceptions = new ArrayList<String>(); - XCompoundTypeDescription[] setExpt = attribute.getSetExceptions(); - for (XCompoundTypeDescription exceptionType : setExpt) { - setExceptions.add( exceptionType.getName() ); - } - memberModel.put( FIELD_SET_EXCEPTIONS, setExceptions ); - - fields.add( memberModel ); + fields.add( getAttributeModel( attribute ) ); } else if ( method != null ) { // TODO Handle the method here - methods.add( memberModel ); + methods.add( getMethodModel( method ) ); } } @@ -409,13 +384,73 @@ public class TypeManager { } /** + * Method object: + * <table border="1"> + * <tr><th>Name</th> <th>Type</th> <th>Description</th></tr> + * <tr><td>name</td><td>String</td><td>the name of the method</td></tr> + * <tr><td>return_type</td><td>Map</td><td>the UNO type returned by the method</td></tr> + * <tr><td>parameters</td><td>sequence of Parameters</td><td>the parameters of the method or an empty list</td></tr> + * <tr><td>exceptions</td><td>sequence of string</td><td>the names of the exceptions or an empty list</td></tr> + * </table> + * + * @param pMethod the method to create the model from + * + * @return the template model object + */ + private Object getMethodModel(XInterfaceMethodTypeDescription pMethod) { + HashMap<String, Object> model = new HashMap<String, Object>(); + + // TODO Complete me + + return model; + } + + /** + * Attribute object: + * <table border="1"> + * <tr><th>Name</th> <th>Type</th> <th>Description</th></tr> + * <tr><td>name</td><td>String</td><td>the name of the attribute</td></tr> + * <tr><td>type</td><td>Map</td><td>the UNO type of the attribute</td></tr> + * <tr><td>get_exceptions</td><td>sequence of string</td><td>the names of the get exceptions or an empty list</td></tr> + * <tr><td>set_exceptions</td><td>sequence of string</td><td>the names of the set exceptions or an empty list</td></tr> + * </table> + * + * @param pAttribute the attribute to create the model from + * + * @return the template model object + */ + public Object getAttributeModel( XInterfaceAttributeTypeDescription2 pAttribute ) { + HashMap<String, Object> model = new HashMap<String, Object>(); + + model.put( FIELD_NAME, pAttribute.getMemberName() ); + model.put( FIELD_TYPE, getTypeModel( pAttribute.getType() ) ); + model.put( FIELD_READONLY, Boolean.valueOf( pAttribute.isReadOnly() ) ); + model.put( FIELD_BOUND, Boolean.valueOf( pAttribute.isBound() ) ); + + ArrayList<String> getExceptions = new ArrayList<String>(); + XCompoundTypeDescription[] getExpt = pAttribute.getGetExceptions(); + for (XCompoundTypeDescription exceptionType : getExpt) { + getExceptions.add( exceptionType.getName() ); + } + model.put( FIELD_GET_EXCEPTIONS, getExceptions ); + + ArrayList<String> setExceptions = new ArrayList<String>(); + XCompoundTypeDescription[] setExpt = pAttribute.getSetExceptions(); + for (XCompoundTypeDescription exceptionType : setExpt) { + setExceptions.add( exceptionType.getName() ); + } + model.put( FIELD_SET_EXCEPTIONS, setExceptions ); + + return model; + } + + /** * type object: * <table border="1"> * <tr><th>Name</th> <th>Type</th> <th>Description</th></tr> * <tr><td>name</td><td>String</td><td>the name of the type</td></tr> - * <tr><td>type</td><td>String</td><td>The type of the UNO type (simple, enum or interface)</td></tr> + * <tr><td>type</td><td>String</td><td>The type of the UNO type (simple or interface)</td></tr> * <tr><td>nested_levels</td><td>Integer</td><td>the number of nested sequences in the type</td></tr> - * <tr><td>TODO name</td><td>type</td><td>description</td></tr> * </table> * * @param pType the UNO type for which to get a model. @@ -435,17 +470,11 @@ public class TypeManager { nestedLevels ++; testedType = xIndDescr.getReferencedType(); } - String type = "simple"; - switch ( testedType.getTypeClass().getValue() ) { - case TypeClass.ENUM_value: - type = "enum"; - break; - case TypeClass.INTERFACE_value: - type = "interface"; - break; - default: - break; + String type = UNO_TYPE_CLASS_SIMPLE; + if ( testedType.getTypeClass().equals( TypeClass.INTERFACE ) ) { + type = UNO_TYPE_CLASS_INTERFACE; } + model.put( UNO_TYPE_CLASS, type ); model.put( UNO_NESTED_LEVELS, Integer.valueOf( nestedLevels) ); |